我是靠谱客的博主 妩媚水池,这篇文章主要介绍虽然我不是做游戏的,闲的没事,emm,写了个扫雷小游戏(Android),现在分享给大家,希望可以做个参考。

文章目录

      • ????老规矩,先上效果图
      • ????需求分析
      • ????实现分析
      • ????代码实现
        • MinefieldUtil
        • RcAdapter
        • MainActivity
      • ????源码下载


????老规矩,先上效果图

在这里插入图片描述


????需求分析

实现扫雷高级版,高级版有30*16的网格,480个格子,99个地雷,381个安全区,通过以下操作逻辑完全避开99个地雷视为通关,可使用小红旗最大数量为99个!

操作逻辑:

  1. 单次长按插小红旗,第二次长按填问号,再次长按恢复正常状态
  2. 单次点击进行开疆扩土,踩到地雷本局游戏结束,并显示所有地雷
  3. 当所有雷排干净时,游戏胜利!

????实现分析

分配2个地图二维数组,一个是雷区,一个是用户操作图

当用户操作是,判断点击位置,上下左右,以及周围的角,进行扩展

当用户第一次点击时,才是创建雷区的时候,防止用户点击上来就炸!!!

通过递归的方式查询,判断周围雷区,开疆扩土!

话不多说,源码开始!!!


????代码实现

代码实现开始了!

MinefieldUtil

公共地图类,这个类承担的作用,如下注释,包含创建,分配地图等,注释写的很详细了,可以直接看:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package com.cyn.traps import android.util.Log import java.util.* /** * 雷区工具类 */ object MinefieldUtil { private const val TAG = "log-trap" //是否已经建立了游戏 var isEstablish = false //剩余小红旗数量 var flagNum = 0 //已排除的格子数量 var turnedOnNum = 0 //是否公开雷区,当公开雷区也就意味着游戏结束,不能再点击 var isOpen = false //创建一张二维数组代表地雷布置 //-1:地雷区域 //0-8:周围地雷数量 val gameMap = Array(16) { Array(30) { 0 } } //用户操作图记录,与地图大小相等 //0:未开采 //1:已开踩 //2:标记小红旗 //3:问号 val operationMap = Array(16) { Array(30) { 0 } } //特殊坐标,该坐标不允许创建雷区 private lateinit var specialCoordinate: MutableList<Int> /** * 创建雷区,当开采第一个方块后,才会开始布置雷区,防止用户上来就炸,并且用户点击处和周围1格不再布置雷区 */ fun establish(dTemp: Int, kTemp: Int) { if (!isEstablish) { isEstablish = true } else { return } //创建特殊坐标 createSpecialCoordinates(dTemp, kTemp) //重置用户操作图 for (d in operationMap.indices) { for (k in operationMap[d].indices) { operationMap[d][k] = 0 } } //剩余小红旗数量重置 flagNum = 99 val random = Random() val temp = mutableSetOf<Int>() //生成要埋地雷的下标 while (true) { val nextInt = random.nextInt(479) dTemp * 30 + kTemp //如果不是用户点击处以及周围1格,才会采取该坐标 if (!specialCoordinate.contains(nextInt)) { temp.add(nextInt) } if (99 == temp.size) { break } } //埋下地雷 for (i in temp) { val d = i / 30 val k = i - 30 * d gameMap[d][k] = -1 } //计算周围地雷数量 createTrapsNumber() //====log Log.d( TAG, "ttt0t1t2t3t4t5t6t7t8t9t10t11t12t13t14t15t16t17t18t19t20t21t22t23t24t25t26t27t28t29" ) Log.d( TAG, "tt--------------------------------------------------------------------------------------------------------------------------" ) for ((c, i) in gameMap.withIndex()) { var str = "$c->tt" for (k in i) { str += k.toString() + "t" } Log.d(TAG, str) } } /** * 获取陷阱数量 */ private fun createTrapsNumber() { for (i in gameMap.indices) { for (j in gameMap[i].indices) { //当此时坐标不是炸弹时候开始计算 if (-1 != gameMap[i][j]) { var trapNum = 0 //查询目标点左侧 if (j - 1 >= 0 && -1 == gameMap[i][j - 1]) { trapNum++ } //查询目标上侧 if (i - 1 >= 0 && -1 == gameMap[i - 1][j]) { trapNum++ } //查询目标右侧 if (j + 1 <= 29 && -1 == gameMap[i][j + 1]) { trapNum++ } //查询目标下侧 if (i + 1 <= 15 && -1 == gameMap[i + 1][j]) { trapNum++ } //查询左上角 if (j - 1 >= 0 && i - 1 >= 0 && -1 == gameMap[i - 1][j - 1]) { trapNum++ } //查询右上角 if (j + 1 <= 29 && i - 1 >= 0 && -1 == gameMap[i - 1][j + 1]) { trapNum++ } //查询右下角 if (j + 1 <= 29 && i + 1 <= 15 && -1 == gameMap[i + 1][j + 1]) { trapNum++ } //查询左下角 if (j - 1 >= 0 && i + 1 <= 15 && -1 == gameMap[i + 1][j - 1]) { trapNum++ } //赋值地雷个数 gameMap[i][j] = trapNum } } } } /** * 创建特殊坐标 */ private fun createSpecialCoordinates(dTemp: Int, kTemp: Int) { specialCoordinate = mutableListOf() //点击位置 specialCoordinate.add(dTemp * 30 + kTemp) //点击坐标左侧 if (kTemp >= 1) { specialCoordinate.add(dTemp * 30 + kTemp - 1) } //点击坐标上侧 if (dTemp >= 1) { specialCoordinate.add((dTemp - 1) * 30 + kTemp) } //点击坐标右侧 if (kTemp <= 28) { specialCoordinate.add(dTemp * 30 + kTemp + 1) } //点击坐标下侧 if (dTemp <= 14) { specialCoordinate.add((dTemp + 1) * 30 + kTemp) } //点击坐标的左上 if (dTemp >= 1 && kTemp >= 1) { specialCoordinate.add((dTemp - 1) * 30 + kTemp - 1) } //点击坐标的右上 if (dTemp >= 1 && kTemp <= 28) { specialCoordinate.add((dTemp - 1) * 30 + kTemp + 1) } //点击坐标的右下 if (dTemp <= 14 && kTemp <= 28) { specialCoordinate.add((dTemp + 1) * 30 + kTemp + 1) } //点击坐标的左下 if (dTemp <= 14 && kTemp >= 1) { specialCoordinate.add((dTemp + 1) * 30 + kTemp - 1) } for (i in specialCoordinate) { Log.d(TAG, i.toString()) } } /** * 重置 */ fun reset() { isEstablish = false isOpen = false turnedOnNum = 0 for (d in gameMap.indices) { for (k in gameMap[d].indices) { gameMap[d][k] = 0 operationMap[d][k] = 0 } } flagNum = 0 } }

RcAdapter

地图适配器,这是一个RecyclerView的适配器,直接用RecyclerView写的,作用是显示地图以及赋予点击事件:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
package com.cyn.traps import android.content.Context import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView class RcAdapter(var context: Context) : RecyclerView.Adapter<RcAdapter.Holder>() { //当游戏失败后,失败处的坐标,此处要着重显示 var overPosition = 0 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder(LayoutInflater.from(context).inflate(R.layout.item_lattice, parent, false)) } override fun getItemCount(): Int { return 480 } override fun onBindViewHolder(holder: Holder, position: Int) { val d = position / 30 val k = position - 30 * d //-1:地雷区域 //0-8:周围地雷数量 val indexGame = MinefieldUtil.gameMap[d][k] //0:未开采 //1:已开踩 //2:标记小红旗 //3:问号 val indexOperation = MinefieldUtil.operationMap[d][k] //判断是否公开雷区 if (MinefieldUtil.isOpen) { //公开雷区,游戏结束 when (indexOperation) { 0, 3 -> { if (indexGame == -1) { holder.itemText.setBackgroundResource(R.mipmap.icon_trap_open) holder.itemText.text = "" } else { holder.itemText.setBackgroundResource(R.mipmap.icon_lattice) holder.itemText.text = "" } } 1 -> { holder.itemText.setBackgroundResource(R.mipmap.icon_empty) holder.itemText.text = indexGame.toString() if (0 != indexGame) { holder.itemText.text = indexGame.toString() } else { holder.itemText.text = "" } holder.itemText.setTextColor( when (indexGame) { 1 -> ContextCompat.getColor(context, R.color.index1) 2 -> ContextCompat.getColor(context, R.color.index2) 3 -> ContextCompat.getColor(context, R.color.index3) 4 -> ContextCompat.getColor(context, R.color.index4) 5 -> ContextCompat.getColor(context, R.color.index5) 6 -> ContextCompat.getColor(context, R.color.index6) 7 -> ContextCompat.getColor(context, R.color.index7) else -> ContextCompat.getColor(context, R.color.index8) } ) } 2 -> { if (indexGame == -1) { holder.itemText.setBackgroundResource(R.mipmap.icon_flag) holder.itemText.text = "" } else { holder.itemText.setBackgroundResource(R.mipmap.icon_flag_error) holder.itemText.text = "" } } } if (indexOperation == 0 && -1 == indexGame) { holder.itemText.setBackgroundResource(R.mipmap.icon_trap_open) holder.itemText.text = "" } if (overPosition == position) { holder.itemText.setBackgroundResource(R.mipmap.icon_trap) holder.itemText.text = "" } } else { //隐藏雷区 when (indexOperation) { 0 -> { holder.itemText.setBackgroundResource(R.mipmap.icon_lattice) holder.itemText.text = "" holder.itemText.setOnClickListener { //开采区域 if (-1 == indexGame) { //踩到地雷,游戏结束 MinefieldUtil.isOpen = true overPosition = position notifyDataSetChanged() dataCallBack?.gameOver() } else { // dataCallBack?.gameWins() //回调游戏开始 if (!MinefieldUtil.isEstablish) { dataCallBack?.gameStart() } //本次点击排除一个格子 MinefieldUtil.turnedOnNum++ //创建地雷,本局游戏只会执行一次,内部已封装好方法 MinefieldUtil.establish(d, k) //递归开采其他模块 exploitation(d, k) //判断是否已经排除完地雷 if (381 == MinefieldUtil.turnedOnNum) { dataCallBack?.gameWins() } //刷新 notifyDataSetChanged() } } holder.itemText.setOnLongClickListener { //在该区域插上小红旗 //判断小红旗是否用完了 if (MinefieldUtil.flagNum <= 0) { return@setOnLongClickListener true } MinefieldUtil.operationMap[d][k] = 2 //回调使用了小红旗 dataCallBack?.useFlag() notifyDataSetChanged() return@setOnLongClickListener true } } 1 -> { if (0 == indexGame) { //已开采周围没有地雷的方块 holder.itemText.setBackgroundResource(R.mipmap.icon_empty) holder.itemText.text = "" } else { //已开采周围有地雷的方块 holder.itemText.setBackgroundResource(R.mipmap.icon_empty) holder.itemText.text = indexGame.toString() holder.itemText.setTextColor( when (indexGame) { 1 -> ContextCompat.getColor(context, R.color.index1) 2 -> ContextCompat.getColor(context, R.color.index2) 3 -> ContextCompat.getColor(context, R.color.index3) 4 -> ContextCompat.getColor(context, R.color.index4) 5 -> ContextCompat.getColor(context, R.color.index5) 6 -> ContextCompat.getColor(context, R.color.index6) 7 -> ContextCompat.getColor(context, R.color.index7) else -> ContextCompat.getColor(context, R.color.index8) } ) } } 2 -> { holder.itemText.setBackgroundResource(R.mipmap.icon_flag) holder.itemText.text = "" holder.itemText.setOnLongClickListener { MinefieldUtil.operationMap[d][k] = 3 dataCallBack?.cancelFlag() notifyDataSetChanged() return@setOnLongClickListener true } } 3 -> { holder.itemText.setBackgroundResource(R.mipmap.icon_doubt) holder.itemText.text = "" holder.itemText.setOnLongClickListener { MinefieldUtil.operationMap[d][k] = 0 notifyDataSetChanged() return@setOnLongClickListener true } } } } } class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) { val itemText: TextView = itemView.findViewById(R.id.itemText) } //============================================================================================== /** * 开采领域,递归调用 */ private fun exploitation(d: Int, k: Int) { if (MinefieldUtil.gameMap[d][k] >= 0) { MinefieldUtil.operationMap[d][k] = 1 if (0 != MinefieldUtil.gameMap[d][k]) { return } //判断左侧是否开采 if (k >= 1 && MinefieldUtil.gameMap[d][k - 1] >= 0 && MinefieldUtil.operationMap[d][k - 1] != 1) { MinefieldUtil.operationMap[d][k - 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d][k - 1] == 0) { exploitation(d, k - 1) } } //判断上侧是否开采 if (d >= 1 && MinefieldUtil.gameMap[d - 1][k] >= 0 && MinefieldUtil.operationMap[d - 1][k] != 1) { MinefieldUtil.operationMap[d - 1][k] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d - 1][k] == 0) { exploitation(d - 1, k) } } //判断右侧是否开采 if (k <= 28 && MinefieldUtil.gameMap[d][k + 1] >= 0 && MinefieldUtil.operationMap[d][k + 1] != 1) { MinefieldUtil.operationMap[d][k + 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d][k + 1] == 0) { exploitation(d, k + 1) } } //判断下侧是否开采 if (d <= 14 && MinefieldUtil.gameMap[d + 1][k] >= 0 && MinefieldUtil.operationMap[d + 1][k] != 1) { MinefieldUtil.operationMap[d + 1][k] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d + 1][k] == 0) { exploitation(d + 1, k) } } //判断左上是否开采 if (d >= 1 && k >= 1 && MinefieldUtil.gameMap[d - 1][k - 1] >= 0 && MinefieldUtil.operationMap[d - 1][k - 1] != 1) { MinefieldUtil.operationMap[d - 1][k - 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d - 1][k - 1] == 0) { exploitation(d - 1, k - 1) } } //判断右上是否开采 if (d >= 1 && k <= 28 && MinefieldUtil.gameMap[d - 1][k + 1] >= 0 && MinefieldUtil.operationMap[d - 1][k + 1] != 1) { MinefieldUtil.operationMap[d - 1][k + 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d - 1][k + 1] == 0) { exploitation(d - 1, k + 1) } } //判断右下是否开采 if (d <= 14 && k <= 28 && MinefieldUtil.gameMap[d + 1][k + 1] >= 0 && MinefieldUtil.operationMap[d + 1][k + 1] != 1) { MinefieldUtil.operationMap[d + 1][k + 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d + 1][k + 1] == 0) { exploitation(d + 1, k + 1) } } //判断左下是否开采 if (d <= 14 && k >= 1 && MinefieldUtil.gameMap[d + 1][k - 1] >= 0 && MinefieldUtil.operationMap[d + 1][k - 1] != 1) { MinefieldUtil.operationMap[d + 1][k - 1] = 1 MinefieldUtil.turnedOnNum++ if (MinefieldUtil.gameMap[d + 1][k - 1] == 0) { exploitation(d + 1, k - 1) } } } } //============================================================================================== //相关事件回调 private var dataCallBack: DataCallBack? = null fun setDataCallBack(dataCallBack: DataCallBack) { this.dataCallBack = dataCallBack } interface DataCallBack { fun gameStart() //游戏结束 fun gameOver() //使用小红旗 fun useFlag() //取消使用小红旗 fun cancelFlag() //游戏胜利 fun gameWins() } }

MainActivity

第一个启动的页面,作用于创建实例!通过它来调用上述两个类来实现的,其功能也写了很详细的注释!可以直接看下面:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package com.cyn.traps import android.annotation.SuppressLint import android.content.Context import android.os.Bundle import android.os.Handler import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { lateinit var rcAdapter: RcAdapter lateinit var flagNum: TextView lateinit var time: TextView lateinit var reset: TextView private var time1 = 0L private var time2 = 0L private val handler: Handler = Handler() //胜利弹框 private lateinit var boxDialog: BoxDialog //计时器 private val mCounter: Runnable = object : Runnable { @SuppressLint("SetTextI18n") override fun run() { handler.postDelayed(this, 1000) time2++ if (60L == time2) { time1++ time2 = 0 } time.text = (if (time1 < 10) "0$time1" else time1.toString()) + ":" + if (time2 < 10) "0$time2" else time2.toString() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //状态栏设置 val titleBar = findViewById<LinearLayout>(R.id.titleBar) StatusBarUtil.immersive(this) StatusBarUtil.darkMode(this) StatusBarUtil.setPaddingSmart(this, titleBar) //控件实例化 flagNum = findViewById(R.id.flagNum) time = findViewById(R.id.time) reset = findViewById(R.id.reset) //加载游戏布局 initView() //重置点击 reset.setOnClickListener { //重新创建游戏 MinefieldUtil.reset() //计时器重置 handler.removeCallbacks(mCounter) time.text = "00:00" //小红旗重置 flagNum.text = "--" //列表刷新 rcAdapter.notifyDataSetChanged() } } @SuppressLint("ClickableViewAccessibility") fun initView() { val rc = findViewById<RecyclerView>(R.id.rc) val layoutParams = rc.layoutParams val pxValue = dip2px(this, 38F) layoutParams.width = pxValue * 30 layoutParams.height = pxValue * 16 rc.layoutManager = GridLayoutManager(this, 30) rcAdapter = RcAdapter(this) rc.adapter = rcAdapter rcAdapter.setDataCallBack(object : RcAdapter.DataCallBack { //游戏开始 override fun gameStart() { time1 = 0 time2 = 0 handler.post(mCounter) } //游戏结束 override fun gameOver() { MinefieldUtil.isEstablish = false flagNum.text = "--" //停止计时 handler.removeCallbacks(mCounter) } //使用小红旗 override fun useFlag() { if (MinefieldUtil.isEstablish) { MinefieldUtil.flagNum-- flagNum.text = MinefieldUtil.flagNum.toString() } } //取消使用小红旗 override fun cancelFlag() { if (MinefieldUtil.isEstablish) { MinefieldUtil.flagNum++ flagNum.text = MinefieldUtil.flagNum.toString() } } //游戏胜利 @SuppressLint("SetTextI18n") override fun gameWins() { //停止计时 handler.removeCallbacks(mCounter) //弹出游戏胜利 val inflate: View = LayoutInflater.from(this@MainActivity) .inflate(R.layout.dialog_win, null, false) val consume = inflate.findViewById<TextView>(R.id.consume) consume.text = "用时:" + (if (time1 < 10) "0$time1" else time1.toString()) + ":" + if (time2 < 10) "0$time2" else time2.toString() val again = inflate.findViewById<TextView>(R.id.again) again.setOnClickListener { //重新创建游戏 time1 = 0 time2 = 0 MinefieldUtil.reset() rcAdapter.notifyDataSetChanged() boxDialog.dismiss() } boxDialog = BoxDialog(this@MainActivity, inflate, BoxDialog.LocationView.CENTER) boxDialog.setCancelable(false)//是否可以点击DialogView外关闭Dialog boxDialog.setCanceledOnTouchOutside(false)//是否可以按返回按钮关闭Dialog boxDialog.show() } }) } /** * dp转px */ private fun dip2px(context: Context, dpValue: Float): Int { val scale: Float = context.resources.displayMetrics.density return (dpValue * scale + 0.5f).toInt() } }

综上所述,完成基本靠以上3个类,这是主要逻辑代码!


????源码下载

CodeChina(推荐):https://codechina.csdn.net/qq_40881680/trap

源码下载:https://download.csdn.net/download/bytedemo/19752276

apk安装包下载:https://download.csdn.net/download/bytedemo/19752267

Github: https://github.com/ThirdGoddess/trap


最后

以上就是妩媚水池最近收集整理的关于虽然我不是做游戏的,闲的没事,emm,写了个扫雷小游戏(Android)的全部内容,更多相关虽然我不是做游戏内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(90)

评论列表共有 0 条评论

立即
投稿
返回
顶部