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

React Native Simon游戏:TouchableOpacity双状态与点击通知实现问题

嘿,刚学React没几天就动手做Simon Says游戏,这进度已经超棒啦!我来帮你一步步解决遇到的问题~

核心问题拆解与解决方案

你的需求本质是要分离「按钮是否可点击」和「按钮样式状态」,同时要捕获用户的点击行为并处理序列。下面是具体实现思路:

1. 统一管理状态

首先把所有需要的状态都放到组件的state里,这样能更清晰地控制按钮状态和游戏流程:

state = {
  canPress: false,         // 控制玩家是否能点击按钮
  isGreenActive: false,    // 绿色按钮的样式激活状态
  isRedActive: false,      // 红色按钮的样式激活状态
  isBlueActive: false,     // 蓝色按钮的样式激活状态
  isYellowActive: false,   // 黄色按钮的样式激活状态
  compSeq: [],             // 电脑生成的序列
  playerSeq: []            // 玩家输入的序列
};

2. 给TouchableOpacity绑定状态与点击事件

直接在TouchableOpacity中通过disabled属性控制是否可点击,同时绑定一个通用的点击处理函数,把按钮标识传进去:

// 绿色按钮示例,其他按钮同理
<TouchableOpacity
  style={[
    styles.greenButton,
    this.state.isGreenActive ? styles.activeButton : null
  ]}
  disabled={!this.state.canPress}  // canPress为true时才允许点击
  onPress={() => this.handleButtonPress('green')}
>
  {/* 按钮内容(比如图标/文字) */}
</TouchableOpacity>

对应的样式可以这样定义,让激活状态有明显视觉变化:

const styles = StyleSheet.create({
  greenButton: {
    backgroundColor: '#2ecc71',
    width: 150,
    height: 150,
    borderRadius: 75,
    margin: 10
  },
  activeButton: {
    opacity: 0.7,  // 激活时降低透明度,或者换更深的颜色
    backgroundColor: '#27ae60'
  },
  // 其他按钮样式...
});

3. 实现点击处理函数,捕获用户操作

这个函数要完成三件事:记录玩家输入、触发按钮闪烁、后续逻辑检查:

handleButtonPress = (buttonType) => {
  // 双重保险:如果不允许点击直接返回
  if (!this.state.canPress) return;

  // 按钮与数值的映射
  const buttonValueMap = {
    green: 1,
    red: 2,
    blue: 3,
    yellow: 4
  };

  // 更新玩家序列(注意setState的异步性,用回调处理后续逻辑)
  this.setState(prevState => ({
    playerSeq: [...prevState.playerSeq, buttonValueMap[buttonType]]
  }), () => {
    // 触发对应按钮的闪烁动画
    this[`${buttonType}Flash`]();
    // 这里可以添加序列检查逻辑,比如判断玩家输入是否和电脑序列匹配
    this.checkPlayerSequence();
  });
};

4. 实现按钮闪烁函数

用Promise封装闪烁逻辑,方便在电脑回合中按顺序播放动画:

greenFlash = () => {
  return new Promise(resolve => {
    // 激活样式
    this.setState({ isGreenActive: true });
    // 300ms后取消激活,完成Promise
    setTimeout(() => {
      this.setState({ isGreenActive: false }, resolve);
    }, 300);
  });
};

// redFlash、blueFlash、yellowFlash同理,替换对应的state字段即可

5. 电脑回合结束后切换到玩家回合

在compTurn函数的最后,等所有闪烁动画完成后,开启玩家点击权限:

compTurn = async () => {
  // 开始电脑回合时,先禁用玩家点击,清空玩家序列
  this.setState({ canPress: false, playerSeq: [] });

  // 遍历电脑序列,逐个播放闪烁动画
  for (const value of this.state.compSeq) {
    // 根据数值找到对应的按钮类型
    const buttonType = Object.keys(buttonValueMap).find(key => buttonValueMap[key] === value);
    // 等待当前按钮闪烁完成
    await this[`${buttonType}Flash`]();
    // 按钮之间的间隔时间
    await new Promise(resolve => setTimeout(resolve, 500));
  }

  // 所有动画完成后,允许玩家点击
  this.setState({ canPress: true });
};

额外小提示

  • 注意setState是异步操作,所以依赖新状态的逻辑要放在setState的回调函数里(比如更新玩家序列后再触发闪烁)。
  • 可以添加checkPlayerSequence函数,在玩家每次点击后检查当前输入是否和电脑序列的对应位置匹配,如果不匹配就触发游戏失败逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:27:50