Kotlin如何按名称/坐标查找数组中房间对象及实现数据存储
安卓网格房间探索功能实现方案
一、房间结构定义:必须替换为data class
你当前用嵌套object定义房间的写法从根上就有问题:Kotlin里的object是全局单例,不管写多少个嵌套object,每个命名object在整个应用生命周期里只有一个实例,根本无法支持动态生成任意数量的新房间,还会出现属性值互相覆盖的问题。
直接用data class定义房间结构是最优选择,它会自动实现结构化相等判断、属性读取、实例复制等能力,完全匹配你存储房间属性的需求:
// 房间数据结构,所有属性和业务字段对齐 data class Room( val x: Long, val y: Long, val z: Long, var exitT: Boolean = false, var exitB: Boolean = false, var exitL: Boolean = false, var exitR: Boolean = false, // 可在此处扩展房间物品、怪物、交互点等其他业务字段 ) { // 按规则生成房间唯一ID:负Y坐标自动加n前缀 val roomId: String get() { val yStr = if (y < 0) "n${-y}" else "$y" return "R${x}_${yStr}_${z}" } }
对应的全局房间管理对象也同步简化,不需要提前写死固定房间的嵌套object,初始状态直接把起始房间加进列表即可:
object Rooms { // 存储所有已生成房间实例的可变列表 val rooms = arrayListOf<Room>() init { // 初始化加入起始房间 R0_0_0,默认四个方向出口全开 rooms.add( Room( x = 0, y = 0, z = 0, exitT = true, exitB = true, exitL = true, exitR = true ) ) } }
二、正确的房间查找&生成逻辑
你之前两个方案的问题非常明确:
- 第一个方案拿生成的房间名字符串,直接和存储Room实例的列表做
contains判断,两边类型完全不匹配,永远不可能匹配成功 - 第二个遍历匹配坐标的思路本身是对的,但受限于单例object的实现问题,加上遍历后没有中断、返回匹配结果,所以无法正常工作
直接用Kotlin标准库的firstOrNull做匹配即可,逻辑简洁不容易出错,替换原来的generateRoom方法:
private fun generateRoom() { // 先按坐标查找已存在的房间 val targetRoom = Rooms.rooms.firstOrNull { it.x == Xcord && it.y == Ycord && it.z == Zcord } if (targetRoom != null) { // 找到已有房间,加载房间数据 println("找到房间${targetRoom.roomId},加载对应数据") // 在此处编写加载房间出口、物品、交互状态的逻辑 } else { // 没找到对应房间,生成新房间实例 val newRoom = Room( x = Xcord, y = Ycord, z = Zcord // 在此处编写新房间出口随机生成、物品刷新的逻辑 ) Rooms.rooms.add(newRoom) println("生成新房间${newRoom.roomId}并加入房间列表") // 加载新房间数据 } }
三、房间数据存储方案
不同存储方案的适用场景和实现方式如下:
- SharedPreferences:只适合存零散的小体积键值对数据,比如玩家当前坐标、游戏设置项。不适合存批量房间结构化数据:如果硬要存,你需要手动把所有房间序列化成JSON字符串再存,读取的时候要全量反序列化,房间数量多了性能极差,维护成本很高。
- 本地持久化(推荐):如果不需要跨设备同步,直接用Jetpack Room数据库做本地存储最合适。给Room实体类加x、y、z三个字段的联合索引,查询的时候直接按三个坐标作为条件查,不需要全量遍历内存列表,哪怕上万个房间查询速度也极快,应用重启后数据不会丢失。
- 在线数据库:如果需要做多设备云存档、多人联机,可以用云文档型数据库,直接把房间的x/y/z坐标拼接成你定义的roomId作为文档唯一标识,查询的时候直接按ID拉取对应文档即可,不需要遍历全量房间数据。
内容的提问来源于stack exchange,提问作者Zytron
相关产品推荐
相关产品推荐

