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

SwiftUI颜色游戏校验失效求助:@State变量未更新及数组匹配问题

解决颜色记忆游戏的校验失效与@State更新问题

我帮你排查出了几个核心问题,咱们一步步来修复:

问题1:按钮索引匹配逻辑完全错误

你的input数组初始化是[1,2,3,4,5,6],但colors数组的索引是从0到5的(绿色对应0、红色对应1,依此类推)。更关键的是,每个按钮的校验逻辑错误地用了input[self.count2],这完全没对应到按钮本身的颜色索引,导致校验永远不会正确触发。

问题2:Timer线程导致@State更新不生效

用Timer.scheduledTimer创建的定时器默认在后台线程运行,直接修改@State变量可能无法触发SwiftUI视图刷新——因为@State的更新必须在主线程执行。

问题3:分数逻辑不一致

只有红色按钮的点击会增加分数,其他按钮没有这个逻辑,导致分数计算完全混乱。


修改后的完整代码

import SwiftUI

struct ContentView: View {
    private let colors = [Color.green, Color.red, Color.blue, Color.pink, Color.orange, Color.purple]
    @State private var currentColor = Color.gray
    @State private var colorSequence = [Int]() // 重命名变量,更清晰表达用途:存储随机颜色索引序列
    @State private var currentStep = 0 // 当前需要校验的序列步骤索引
    @State private var score = 0
    @State private var isShowingSequence = false // 标记是否正在展示颜色序列
    
    // 生成随机颜色序列并开始展示
    func startNewRound() {
        colorSequence = Array(repeating: 0, count: 6).map { _ in Int.random(in: 0...5) }
        currentStep = 0
        isShowingSequence = true
        showNextColor(index: 0)
    }
    
    // 递归展示颜色序列(确保在主线程更新UI)
    func showNextColor(index: Int) {
        guard index < colorSequence.count else {
            isShowingSequence = false
            return
        }
        currentColor = colors[colorSequence[index]]
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            showNextColor(index: index + 1)
        }
    }
    
    // 处理颜色按钮点击的校验逻辑
    func onColorTap(_ colorIndex: Int) {
        guard !isShowingSequence else { return } // 展示序列时禁止点击按钮
        
        if colorIndex == colorSequence[currentStep] {
            currentStep += 1
            score += 1
            
            // 完成一轮校验后,自动开启下一轮
            if currentStep == colorSequence.count {
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    startNewRound()
                }
            }
        } else {
            // 错误时重置分数和步骤
            score = 0
            currentStep = 0
        }
    }
    
    var body: some View {
        VStack{
            Spacer()
            // 颜色展示区
            Rectangle()
                .foregroundColor(currentColor)
                .frame(height: 150)
                .cornerRadius(10)
                .padding()
            
            Spacer()
            
            HStack{
                Button(action: startNewRound) {
                    Text("Start")
                        .padding()
                        .background(Color.blue)
                        .foregroundColor(.white)
                        .cornerRadius(8)
                }
                .disabled(isShowingSequence) // 展示序列时禁用Start按钮
                
                Text("步骤: \(currentStep + 1)/6")
                    .font(.headline)
                
                Text("分数: \(score)")
                    .font(.headline)
                    .foregroundColor(.green)
            }
            .padding()
            
            Spacer()
            
            // 颜色按钮区
            VStack(spacing: 16) {
                HStack(spacing: 16) {
                    ColorButton(color: colors[0], action: { onColorTap(0) })
                    ColorButton(color: colors[1], action: { onColorTap(1) })
                    ColorButton(color: colors[2], action: { onColorTap(2) })
                }
                HStack(spacing: 16) {
                    ColorButton(color: colors[3], action: { onColorTap(3) })
                    ColorButton(color: colors[4], action: { onColorTap(4) })
                    ColorButton(color: colors[5], action: { onColorTap(5) })
                }
            }
            .padding()
        }
        .padding()
    }
}

// 提取颜色按钮为子视图,减少代码重复
struct ColorButton: View {
    let color: Color
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            Rectangle()
                .foregroundColor(color)
                .frame(width: 80, height: 80)
                .cornerRadius(12)
                .shadow(radius: 4)
        }
        .disabled(ContentView().isShowingSequence) // 展示序列时禁用所有颜色按钮
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

关键修改说明

  • 修复核心校验逻辑:每个颜色按钮点击时传递自己对应的索引(0-5),直接和colorSequence[currentStep]对比,终于能正确校验顺序。
  • 主线程更新UI:用DispatchQueue.main.asyncAfter替代后台Timer,确保@State变量在主线程更新,视图能及时响应变化。
  • 统一分数逻辑:所有正确点击都会加分,错误点击直接重置分数和步骤,逻辑一致。
  • 用户体验优化:展示序列时禁用所有交互按钮,防止误操作;完成一轮后自动开启下一轮;优化了按钮样式和布局,视觉效果更友好。
  • 代码结构优化:提取颜色按钮为子视图,减少重复代码,后续维护更方便;重命名变量让代码可读性大幅提升。

内容的提问来源于stack exchange,提问作者Jeff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:57:27