我需要为我刚开始制作的应用程序做一些复杂的事情,我不知道我会怎么做。一切都是这样运作的。我有一个包含“房间”的对象,玩家已经生成和探索了。这些“房间”中的每一个都是另一个对象,包含该特定房间的数据,如其位置,或该房间中的项目。第一个对象中也有一个数组,它包含所有的"room“对象。当用户生成以前没有访问过的新房间时,将以编程方式创建这些对象,并且对象的名称将根据房间的位置生成(我也不知道该如何做,但这是未来的问题)。
我需要做的第一件事是搜索第一个名为“Room”的对象中的数组,以寻找另一个名称与播放器位置匹配的对象。这是由3个变量决定的,这些变量决定了玩家在房间网格上的位置。所以0,0,0将是起始位置,例如,如果玩家向右移动1个房间,向后移动2个房间,然后向上移动1层,玩家的位置将是X: 1,Y:-2,Z: 1。这个房间的对象名为"R1_n2_1“,所以游戏将搜索一个名为"R1_n2_1”的对象,并在找到它时加载它。但是,如果没有具有匹配名称的对象,那么它将生成一个新房间,并将这个新房间的数据添加为另一个对象,该对象的名称与它正在寻找的对象(“R1_n2_1”)相匹配,然后新对象也将被添加到指定所有这些“房间”/objects的数组中(正如前面提到的那样,稍后我将知道这一点)。
我需要的是如何通过编程方式生成要查找的对象名,然后查找其名称与之匹配的对象名称,从而搜索对象名称。例如,我的当前代码几乎肯定无法工作,但它会传递想法,生成它正在寻找的对象名称的字符串,然后搜索数组以找到匹配的对象。但是,它将永远找不到这个匹配,因为它正在寻找一个字符串,而不是一个具有匹配名称的对象。
class GameActivity : AppCompatActivity() {
private var exitedFrom = "start" //start; l; r; t; b; tunnel; ladder; ?;
private var Xcord: Long = 0
private var Ycord: Long = 0
private var Zcord: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
fullscreen()
generateRoom()
}
private fun generateRoom() {
val room = "R$Xcord"+"_$Ycord"+"_$Zcord"
if (Rooms.rooms.contains(room)) {
//load the room
println("room $room found")
} else println("room $room not found.") //result is always this
}这是我所有房间的对象。模板将被克隆以生成一个新的房间,而R0__0是开始的空间。
object Rooms {
object Template {
var x = 0
var y = 0
var z = 0
var exitT = false
var exitB = false
var exitL = false
var exitR = false
}
object R0_0_0 { //R(x)_(y)_(z)
var x = 0
var y = 0
var z = 0
var exitT = true
var exitB = true
var exitL = true
var exitR = true
}
var rooms = arrayListOf(Template, R0_0_0)
}更新:我的第一个想法就是根本不关心对象名,搜索数组中列出的每个对象,以匹配位置变量(x、y、z)。但是,这是行不通的,因为一旦数组有了多个对象,它就不能搜索数组中的所有内容,以便在任何变量中匹配。这是一种功能:
private fun generateRoom() {
Rooms.rooms.forEach {
if(it.x == Xcord && it.y == Ycord && it.z == Zcord) {
println("Room Found")
}
}
}有办法绕过这件事还是我该做点别的?“数据类”能代替对象吗?我不知道数据类是如何工作的,但它们听起来很有希望。我已经开始尝试一些东西,但我不知道它将如何工作。任何其他的想法或工作解决方案将是非常有帮助的!
最后一个问题:您能用SharedPreferences或在线数据库保存这些对象吗?如果是,如何保存?
发布于 2022-06-16 01:51:22
我想首先指出几点:
object (var属性或引用可变类实例的val属性)。这往往会使代码变得脆弱(很容易引入bug),因为共享状态可以很容易地从任何地方更改,并且使编写测试代码变得非常困难。如果你对它们不小心的话,它们也会导致内存泄漏。Template和R0_0_0转换为类,它们也是一种荒谬的设计。它们具有相同的属性,因此它们应该是同一个类。在类名中有坐标是没有意义的。如果您有一个10x10x10网格,您是否要用相同的属性手动定义1000个类?您只需要在运行时生成一个不确定的实例数的类。,
onSavedInstanceState对其进行备份,并在配置更改后恢复它。简单的解决方案是将那些表示游戏状态的属性移动到ViewModel.exitedFrom变量.至于你要问的问题,这是一个适合MutableMap的自然选择。一个映射通过唯一的键保存条目,在映射中的每个键都可以保存一个值(在本例中,是Room类的一个实例)。映射被设计成能够非常有效地按键查找值,但是如果需要这样做,您也可以高效地迭代它们以找到一些东西。
键应该是正确实现hashcode()和equals()的类的成员,这很容易使用数据类自动完成。在这种情况下,自然键类型将是一个表示坐标的类。选择一个不可变的键类也很重要,以避免潜在的bug,因此这个坐标类的所有属性都应该是val的。
因此,把所有这些放在一起,下面是我如何修复您的代码,并提供了几个示例函数来回答您关于查找房间的问题。
// Classes representing game state:
// This class is immutable and a data class so we can safely use it as a Map key.
// When we want to make changes, we use the copy() function to create
// a new instance of the class.
data class Coordinate(
val x: Long = 0,
val y: Long = 0,
val z: Long = 0
) {
// Convenience functions:
fun movedByX(amount: Long) = copy(x = x + amount)
fun movedByY(amount: Long) = copy(y = y + amount)
fun movedByZ(amount: Long) = copy(z = z + amount)
}
class Room(val coordinate: Coordinate) {
var exitT = true
var exitB = true
var exitL = true
var exitR = true
// I assume you'll add other properties such as whether it has a ladder
// going up and/or down, etc.
)
// Enum to replace the String you were using for tracking movement direction
enum class Movement {
Start, Left, Right, Top, Bottom, UpLadder, DownLadder
}class GameActivity : AppCompatActivity() {
// Read the Android docs about ViewModels to understand why we
// instantiate it this way.
val viewModel: GameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
fullscreen()
// Set up the UI that draws stuff based on properties of the
// viewModel and calls functions of the viewModel when the user
// clicks stuff.
}
}class GameViewModel: ViewModel() {
var playerCoordinate = Coordinate()
private var exitedFrom = Movement.Start
// The Map containing all rooms that have been created in the game session.
private val rooms = mutableMapOf<Coordinate, Room>()
// This optional property is just a convenient shortcut.
val currentRoom: Room
get() = rooms.getValue(playerCoordinate)
init {
// Create the initial room by moving there
move(Movement.Start)
}
fun move(movement: Movement) {
exitedFrom = movement // I'm not sure if you really need this exitedFrom
// property but if you do, you can back it up here.
playerCoordinate = when (movement) {
Start -> Coordinate()
Left -> playerCoordinate.moveX(-1L)
Right -> playerCoordinate.moveX(1L)
Bottom -> playerCoordinate.moveY(-1L)
Top -> playerCoordinate.moveY(1L)
DownLadder -> playerCoordinate.moveZ(-1L)
UpLadder -> playerCoordinate.moveZ(1L)
}
// Create the room if it doesn't exist yet.
if (!rooms.containsKey(playerCoordinate)) {
val newRoom = Room(playerCoordinate).apply {
// Customize the new room's properties here. Maybe randomized?
// probably want to use the movement to ensure there is an exit
// coming from the direction that was moved from so player
// can backtrack.
}
rooms[playerCoordinate] = newRoom
}
}
fun resetGame() {
rooms.clear()
move(Movement.Start)
}
}发布于 2022-06-16 01:53:55
可以通过对象属性、对象类型或对象类型的字符串表示形式搜索对象列表。最后一个是(我认为)您想要做的事情(但它可能不是最可扩展的代码设计选择)。
按对象属性搜索
如果您只想根据对象的属性搜索对象列表,可以使用列表上的find函数搜索与某些谓词匹配的对象,如下所示:
class Room(var name: String)
fun hasRoom(name: String, rooms: List<Room>): Boolean {
return rooms.find { it.name == name } != null
}
val rooms = listOf(Room("A"), Room("B"), Room("C"))
hasRoom("A", rooms) // true
hasRoom("D", rooms) // false您还可以为此操作或其他常见操作为您的房间列表定义扩展函数:
fun List<Room>.containsName(name: String): Boolean {
return this.find { it.name == name } != null
}这将使您可以直接在房间列表上调用containsName,类似于您正在尝试做的事情:
val rooms = listOf(Room("A"), Room("B"), Room("C"))
rooms.containsName("A") // true
rooms.containsName("D") // false另外,正如另一个答案所指出的那样,您肯定应该在这里使用一个带有属性的类,而不是为每个坐标使用一个新的类类型。坐标可以是类的属性,上面的属性搜索方法仍然适用。
按对象类型搜索
如果您真的想按对象类型而不是对象的属性搜索对象列表,仍然可以使用扩展函数进行搜索:
class Room
class House
class Yacht
class Boat
inline fun <reified K> List<Any>.containsObj(): Boolean {
return this.filterIsInstance<K>().isNotEmpty()
}
val rooms = listOf(Room(), House(), Yacht())
rooms.containsObj<House>() // true
rooms.containsObj<Boat>() // false按对象类型名称搜索
如果您真的想根据类型的字符串名称进行搜索,您也可以这样做。
fun List<Any>.containsObjName(name: String): Boolean {
return this.find { it::class.simpleName == name } != null
}
val rooms = listOf(Room(), House(), Yacht())
rooms.containsObjName("House") // true
rooms.containsObjName("Boat") // falsehttps://stackoverflow.com/questions/72638011
复制相似问题