2011-09-07 112 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