You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:25:24