SwiftUI开发D&D掷骰工具:通用掷骰函数失效问题求助
D&D掷骰应用通用函数失效问题与解决方案
原代码的核心问题
你的rollStat函数无法生效,根源在于值类型的拷贝特性:
- Swift中数组、Int都是值类型,当你把
strArray、strStat存入allArrays、allStats时,实际是创建了一份副本,而非引用原@State变量。 - 后续对
allArrays、allStats的修改只会作用在副本上,根本不会更新原@State变量,自然无法反映到UI上。
同时,原代码用零散变量管理6组属性数据,重复冗余,也增加了通用化的难度。
优化方案:重构数据结构+通用函数
步骤1:统一属性数据结构
先定义结构体封装单个属性的掷骰记录和最终值,替代零散变量:
struct CharacterStat { var rolls: [Int] = [0, 0, 0] var finalValue: Int = 0 }
再用一个@State数组管理所有6个属性(顺序对应力量、敏捷、体质、智力、感知、魅力):
@State private var stats: [CharacterStat] = Array(repeating: CharacterStat(), count: 6)
步骤2:编写通用掷骰逻辑
先封装生成"掷3枚d6求和"的工具函数,再实现通用属性更新函数:
// 生成一次3d6的求和结果 func roll3d6() -> Int { return (1...3).reduce(0) { sum, _ in sum + Int.random(in: 1...6) } } // 通用属性掷骰函数:传入属性索引,更新对应数据 func rollStat(at index: Int) { guard index < stats.count else { return } // 生成三次3d6的结果 let newRolls = [roll3d6(), roll3d6(), roll3d6()] // 更新掷骰记录和最终最大值 stats[index].rolls = newRolls stats[index].finalValue = newRolls.max()! }
步骤3:批量更新所有属性
按钮点击时,遍历所有属性索引调用通用函数即可:
Button(action: { for index in 0..<stats.count { rollStat(at: index) } }) { rollButton() }
步骤4:更新UI显示
把原来的零散Text替换为遍历stats数组的方式:
// 最终属性值显示 VStack(spacing: 16) { ForEach(stats.indices, id: \.self) { index in Text(String(stats[index].finalValue)) } } // 掷骰记录显示 VStack(alignment: .leading, spacing: 16) { ForEach(stats.indices, id: \.self) { index in let rolls = stats[index].rolls Text("\(rolls[0]), \(rolls[1]), \(rolls[2])") } }
完整重构后的核心代码片段
struct ContentView: View { // 定义属性结构体 struct CharacterStat { var rolls: [Int] = [0, 0, 0] var finalValue: Int = 0 } // 用数组统一管理6个属性 @State private var stats: [CharacterStat] = Array(repeating: CharacterStat(), count: 6) // 生成一次3d6的求和结果 func roll3d6() -> Int { return (1...3).reduce(0) { sum, _ in sum + Int.random(in: 1...6) } } // 通用属性掷骰函数 func rollStat(at index: Int) { guard index < stats.count else { return } let newRolls = [roll3d6(), roll3d6(), roll3d6()] stats[index].rolls = newRolls stats[index].finalValue = newRolls.max()! } var body: some View { VStack { HStack(spacing: 10) { VStack(spacing: 6) { sixDiceView() sixDiceView() sixDiceView() sixDiceView() sixDiceView() sixDiceView() } statNames() ZStack { VStack(spacing: 16) { ForEach(stats.indices, id: \.self) { index in Text(String(stats[index].finalValue)) } } VStack(spacing: 6) { ForEach(0..<6) { _ in Capsule() .fill(Color.blue.opacity(0.2)) .frame(width: 60, height: 30) } } } ZStack { rollsCapsule() VStack(alignment: .leading, spacing: 16) { ForEach(stats.indices, id: \.self) { index in let rolls = stats[index].rolls Text("\(rolls[0]), \(rolls[1]), \(rolls[2])") } } } } Button(action: { for index in 0..<stats.count { rollStat(at: index) } }) { rollButton() } } } // 保留原自定义视图函数实现 func sixDiceView() -> some View { Text("🎲🎲🎲") } func statNames() -> some View { VStack(spacing: 16) { Text("力量") Text("敏捷") Text("体质") Text("智力") Text("感知") Text("魅力") } } func rollsCapsule() -> some View { VStack(spacing: 6) { ForEach(0..<6) { _ in Capsule() .fill(Color.gray.opacity(0.1)) .frame(width: 100, height: 30) } } } func rollButton() -> some View { Text("Roll") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } }
内容的提问来源于stack exchange,提问作者Naxx
相关产品推荐
相关产品推荐

