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

基于TwinCAT结构化文本的类Simon记忆游戏按键校验及计数问题咨询

TwinCAT结构化文本开发Simon游戏:按键校验与错误统计方案

你用TwinCAT ST做Simon记忆游戏遇到的这两个问题,其实核心是要先把游戏的序列管理和用户输入追踪逻辑理清楚。我结合你现有的代码片段,给你调整和补充下实现思路:

一、先完善必要的变量定义

首先得补充几个核心变量来管理游戏状态、序列存储和用户输入:

VAR
    // 原有变量
    iRandomNumber: DINT;
    fb_delay : ton;
    Run: BOOL;
    GameSpeed: TIME:= T#2S;
    io.blue: bool;
    io.red: bool; // 假设还有其他颜色LED,根据你的硬件补充
    io.green: bool;
    io.yellow: bool;
    io.start: bool;
    io.blue_btn: bool; // 对应蓝色按键
    io.red_btn: bool;
    io.green_btn: bool;
    io.yellow_btn: bool;

    // 新增游戏管理变量
    aGameSequence: ARRAY[1..20] OF DINT; // 存储随机生成的LED序列,最多20步
    aUserInput: ARRAY[1..20] OF DINT; // 存储用户按下的按键序列
    iCurrentStep: DINT := 0; // 当前游戏序列的长度
    iShowIndex: DINT := 0; // 序列展示时的当前索引
    iUserInputIndex: DINT := 0; // 用户当前输入的索引
    bInputPhase: BOOL := FALSE; // 是否处于用户输入阶段
    iErrorCount: DINT := 0; // 累计错误次数
    iLastWrongInputCount: DINT := 0; // 记录上次错误时已按下的按键数
    fb_btn_delay: ton; // 按键消抖用延时块
END_VAR

二、校验按键操作与亮起的LED是否一致

Simon游戏的逻辑是先展示随机序列→再让用户按顺序重复,所以要拆分「序列展示阶段」和「用户输入阶段」,在输入阶段逐个对比用户按键和序列值:

1. 生成并展示序列

当启动游戏后,先生成随机序列,逐个点亮对应LED:

// 启动游戏逻辑
IF io.start THEN
    Run := TRUE;
    iCurrentStep := 1; // 初始化第一步序列
    iShowIndex := 0;
    // 生成第一个随机数(1-4对应四个颜色)
    iRandomNumber := RANDOM(1,4);
    aGameSequence[iCurrentStep] := iRandomNumber;
    fb_delay(in:=TRUE, PT:=GameSpeed); // 启动展示延时
END_IF

// 序列展示逻辑:逐个点亮LED
IF Run AND NOT bInputPhase THEN
    IF iShowIndex < iCurrentStep THEN
        // 熄灭所有LED,准备点亮当前序列的LED
        io.blue := FALSE;
        io.red := FALSE;
        io.green := FALSE;
        io.yellow := FALSE;

        iShowIndex := iShowIndex + 1;
        // 根据序列值点亮对应LED
        CASE aGameSequence[iShowIndex] OF
            1: io.blue := TRUE;
            2: io.red := TRUE;
            3: io.green := TRUE;
            4: io.yellow := TRUE;
        END_CASE;
        fb_delay(in:=TRUE, PT:=GameSpeed); // 启动当前LED的点亮延时
    ELSIF fb_delay.Q THEN
        // 序列展示完毕,切换到用户输入阶段
        io.blue := FALSE;
        io.red := FALSE;
        io.green := FALSE;
        io.yellow := FALSE;
        bInputPhase := TRUE;
        iUserInputIndex := 0;
    END_IF;
END_IF

2. 用户输入校验

在输入阶段,捕捉按键动作并实时和序列对应位置对比:

// 用户输入处理:仅在输入阶段响应按键
IF bInputPhase THEN
    // 按键消抖处理:避免单次按键被识别多次
    IF fb_btn_delay.Q THEN
        fb_btn_delay(in:=FALSE);
    END_IF;

    // 捕捉各颜色按键输入
    IF io.blue_btn AND NOT fb_btn_delay.Q THEN
        iUserInputIndex := iUserInputIndex + 1;
        aUserInput[iUserInputIndex] := 1;
        fb_btn_delay(in:=TRUE, PT:=T#200MS);
    ELSIF io.red_btn AND NOT fb_btn_delay.Q THEN
        iUserInputIndex := iUserInputIndex + 1;
        aUserInput[iUserInputIndex] := 2;
        fb_btn_delay(in:=TRUE, PT:=T#200MS);
    ELSIF io.green_btn AND NOT fb_btn_delay.Q THEN
        iUserInputIndex := iUserInputIndex + 1;
        aUserInput[iUserInputIndex] := 3;
        fb_btn_delay(in:=TRUE, PT:=T#200MS);
    ELSIF io.yellow_btn AND NOT fb_btn_delay.Q THEN
        iUserInputIndex := iUserInputIndex + 1;
        aUserInput[iUserInputIndex] := 4;
        fb_btn_delay(in:=TRUE, PT:=T#200MS);
    END_IF;

    // 每次输入后校验是否匹配序列
    IF iUserInputIndex > 0 THEN
        // 输入错误的情况
        IF aUserInput[iUserInputIndex] <> aGameSequence[iUserInputIndex] THEN
            bInputPhase := FALSE;
            Run := FALSE;
            iLastWrongInputCount := iUserInputIndex; // 记录错误时已按下的按键数
            iErrorCount := iErrorCount + 1;
            // 可添加错误提示逻辑,比如闪烁所有LED
        // 输入正确且完成当前序列的情况
        ELSIF iUserInputIndex = iCurrentStep THEN
            bInputPhase := FALSE;
            iCurrentStep := iCurrentStep + 1;
            // 生成新的随机数加入序列
            iRandomNumber := RANDOM(1,4);
            aGameSequence[iCurrentStep] := iRandomNumber;
            // 准备展示新序列
            iShowIndex := 0;
            fb_delay(in:=TRUE, PT:=GameSpeed);
        END_IF;
    END_IF;
END_IF

三、按键错误时统计已按下的按键数量

上面的代码已经包含了这个逻辑:当检测到用户输入和序列不一致时,把当前的iUserInputIndex赋值给iLastWrongInputCount,这个变量就精准记录了错误发生时用户已经按下的按键数量。

比如用户在第3步输入错误,iUserInputIndex此时是3,那么iLastWrongInputCount就会被设为3,你可以把这个值输出到HMI、存储到变量或者用于后续的游戏逻辑判断。

额外提醒

  • 按键消抖是必须的,不然会出现单次按键被识别多次的误判
  • TwinCAT的RANDOM函数需要初始化种子,不然每次启动游戏都会生成相同的序列
  • 可以根据游戏进度动态调整GameSpeed,比如每完成5步就缩短展示时长,增加游戏难度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:05:01