2011-09-07 77 views
7
在地图中关键

我的游戏类类型Scala的

class Enemy 

谁的AI /功能,我可以

trait Moving 
trait VerticalMover extends Moving 
trait RandomMover extends Moving 

等改变。现在我需要根据特质获取预装的东西。我想要做的是有一个Map接受所有扩展移动特性的特征,然后将一些EnemyContainer作为值预先加载特征相关内容。

但我怎么定义这样的地图,以及如何做格式化我获得()被一些敌人的一个实例,以获得容器。例如:

val myEnemy = new Enemy with RandomMover 
val myDetails:EnemyContainer = enemyDetailsStore.get(myEnemy.getClass) 
+0

你的意思是你想要的'enemyDetailsS​​tore'返回一个事情,如果'myEnemy'延伸'VerticalMover',还有一件事,如果它延伸'RandomMover'?如果它同时延伸呢? –

+0

是的,这就是我的意思。但我开始怀疑我的整个想法的理智。也许我应该在特征中嵌入一些关键字串并将其用作关键字。因此,在特质线性化的情况下,最后一个压倒性的特性会将EnemyContainer设置为用于显示敌人的纹理。 – vertti

+3

大多数时候,特质/界面的要点是说“我知道怎么做* X *”,同时允许X的不同实现。在没有其他细节的情况下,我会认为最自然的设计会应该让'Moving'特性直接具有某种'getMovingStrategy'或'move'方法,您可以在垂直和随机移动器相减中实现相应的功能。 –

回答

5

那么,我认为你的敌人的详细信息存储类型为Map[Class[_ <: Moving], EnemyDetails]。我怀疑,是这样的:

//gives a Map[Class[_ <: Moving], EnemyDetails] for all matching keys 
enemyDetailsStore.filterKeys(_ isInstance myEnemy) 

或者:

//Iterable[EnemyDetails] 
enemyDetailsStore collect { case (c, d) if c isInstance myEnemy => d } 

甚至只是:

//Option[EnemyDetails] 
enemyDetailsStore collectFirst { case (c, d) if c isInstance myEnemy => d } 

会为你做。唯一的“问题”这个代码是它的O(N),因为它需要在地图的遍历,而不是一个简单的查找,这将是O(1),或者为O(log N)

10

也许你可以包装一个Map [Manifest,Any],确保这些值对应于清单键。

可能的草图。首先一个小帮手

class Typed[A](value: A)(implicit val key: Manifest[A]) { 
    def toPair: (Manifest[_], Any) = (key, value) 
} 
object Typed { 
    implicit def toTyped[A: Manifest](a: A) = new Typed(a) 
    implicit def toTypable[A](a: A) = new { 
    def typedAs[T >: A : Manifest] = new Typed[T](a)(manifest[T]) 
    } 
} 

然后包装本身(这是不是一个地图)

class TypedMap private(val inner: Map[Manifest[_], Any]) { 
    def +[A](t: Typed[A]) = new TypedMap(inner + t.toPair) 
    def +[A : Manifest](a: A) = new TypedMap(inner + (manifest[A] -> a)) 
    def -[A : Manifest]() = new TypedMap(inner - manifest[A]) 
    def apply[A : Manifest]: A = inner(manifest[A]).asInstanceOf[A] 
    def get[A : Manifest]: Option[A] = inner.get(manifest[A]).map(_.asInstanceOf[A]) 
    override def toString = inner.toString 
    override def equals(other: Any) = other match { 
    case that: TypedMap => this.inner == that.inner 
    case _ => false 
    } 
    override def hashCode = inner.hashCode 
} 

object TypedMap { 
    val empty = new TypedMap(Map()) 
    def apply(items: Typed[_]*) = new TypedMap(Map(items.map(_.toPair) : _*)) 
} 

有了,你可以做

import Typed._ 
val repository = TypedMap("foo", 12, "bar".typedAs[Any]) 

库:TypedMap =地图(Java .lang.String - > FOO,INT - >如图12所示,任一 - > 巴)

您检索元素与

repository[String] // returns "foo" 
repository.get[Any] // returns Some("bar") 

我认为私有的构造应确保_ asInstanceOf是安全的。 inner可能会被公开,因为它是不可变的。这样,Map的丰富接口将可用,但不幸的是,不会创建另一个TypedMap