Search code examples
reactjscomponentsreact-native

calling a function inside a component


I'm working on a simon-says game as my first React Native app.

The idea is to show the player the sequence according to the round we're in, then let the player press a button, check if that button matches the given seq, if so then let the user press again, calling the function check again. if he did ok in the end of the round then I increase round etc, and then show the sequence again. If the player fails the game will stop until the user press start again.

I don't know how to set a loop that will enable the player to press the buttons untill round is over, because this function is called only on press, so I have no idea how to control it.

The idea is to show the player the sequence according to the round we're in, then let the player press a button, check if that button matches the given seq, then let the user press again, calling the function check again. if he did ok, then I increase round etc, and then show the sequence again.

all this should loop from round 1 to seq.length.

any ideas? my code below. thanks!

import React, {Component} from 'react';
import {StyleSheet, Text, View,TouchableOpacity, Button, Image} from 'react-native';
export default class App extends Component{ 
  constructor (props){
    super(props);
    this.flash=0
    this.round=1
    this.seq=[] 
    this.playerSeq=[] 
    this.win=false
    this.ok=true
    this.score=0
    this.state = {
      canPress: false,
      greenB: {
        backgroundColor: 'darkgreen'
      },
      yellowB: {
        backgroundColor: 'orange'
      },
      blueB: {
        backgroundColor: 'blue'
      },
      redB: {
        backgroundColor: 'red'
      }
    }
    this.play=this.play.bind(this)
    this.greenFlash=this.greenFlash.bind(this)
    this.blueFlash=this.blueFlash.bind(this)
    this.redFlash=this.redFlash.bind(this)
    this.playerTurn=this.playerTurn.bind(this)
    this.check=this.check.bind(this)
  }

  play(){
    this.seq=[1,2,3,1,4] //will be random, this is just for testing
    this.playerSeq=[] 
    this.flash=0
    this.round=1
    this.win=false
    this.ok=true
    this.score=0
    this.compTurn()
    this.setState({canPress: true})
  } 

  playerTurn(i){
    this.flash=0
    this.playerSeq[this.flash]=i
    this.setState({canPress: false})
    this.check()
  }

  check(){ 
    if (this.playerSeq[this.flash]==this.seq[this.flash]){
      if (this.playerSeq[this.flash]==1){
        this.greenFlash();
      }
      if (this.playerSeq[this.flash]==2){
        this.yellowFlash();
      }
      if (this.playerSeq[this.flash]==3){
        this.blueFlash();
      }
      if (this.playerSeq[this.flash]==4){
        this.redFlash();
      }
      this.flash++
      this.ok=true
      this.setState({canPress: true})
      if (this.flash==this.round){
        this.setState({canPress: false})
        this.round++
        }
      }
      else {
        this.ok=false;
      }
    }

    compTurn() {
      let intervalId = setInterval(()=> {
        if (this.flash==this.round) {
          clearInterval(intervalId);
        }
        else {
          if (this.seq[this.flash]==1){
            this.greenFlash();
          }
          if (this.seq[this.flash]==2){
            this.yellowFlash();
          }
          if (this.seq[this.flash]==3){
            this.blueFlash();
          }
          if (this.seq[this.flash]==4){
            this.redFlash();
          }
          this.flash++;
        }
      }
      , 1500);    
      this.setState({canPress: true})
      this.flash=0;
    }

  compTurn() {
      let intervalId = setInterval(()=> {
        if (this.flash==this.round) {
          clearInterval(intervalId);
        }
        else {
          if (this.seq[this.flash]==1){
            this.greenFlash();
          }
          if (this.seq[this.flash]==2){
            this.yellowFlash();
          }
          if (this.seq[this.flash]==3){
            this.blueFlash();
          }
          if (this.seq[this.flash]==4){
            this.redFlash();
          }
          this.flash++;
        }
      }
      , 1500);  

      this.setState({canPress: true})
      //this.userTurn=true;
      this.flash=0;
  }

  greenFlash(){
      setTimeout(() => {
        this.setState( {
            greenB:{
              ...this.state.style1, backgroundColor: 'lightgreen'
            }
            })
        }, 200);
      setTimeout(() => {
        this.setState( {
            greenB:{
              ...this.state.style1, backgroundColor: 'darkgreen'
            }
            })
        }, 1000);
  } 

  yellowFlash(){
    setTimeout(() => {
      this.setState( {
          yellowB:{
            ...this.state.style1, backgroundColor: 'yellow'
          }
          })
      }, 200);
    setTimeout(() => {
      this.setState( {
          yellowB:{
            ...this.state.style1, backgroundColor: 'orange'
          }
          })
        }, 1000);
  }

  blueFlash(){
    setTimeout(() => {
      this.setState( {
          blueB:{
            ...this.state.style1, backgroundColor: 'lightblue'
          }
          })
      }, 200);
    setTimeout(() => {
      this.setState( {
          blueB:{
            ...this.state.style1, backgroundColor: 'blue'
          }
          })
        }, 1000);
  }

  redFlash(){
    setTimeout(() => {
      this.setState( {
          redB:{
            ...this.state.style1, backgroundColor: 'pink'
          }
          })
      }, 200);
    setTimeout(() => {
      this.setState( {
          redB:{
            ...this.state.style1, backgroundColor: 'red'
          }
          })
        }, 1000);
  }

  render(){
    return (
      <View>
        <TouchableOpacity style={styles.playB}
        onPress={this.play}> 
        <Text style={{
          color:'white',
          height: 30,
          width:60,
          }}>START</Text>
        </TouchableOpacity>
        <TouchableOpacity style={[
          styles.greenB,
          this.state.greenB]} 
          onPress={this.state.canPress ? (()=> this.playerTurn(1)) : null}></TouchableOpacity>
        <TouchableOpacity style={[
          styles.yellowB,
          this.state.yellowB]} 
          onPress={this.state.canPress ? (()=> this.playerTurn(2)) : null}></TouchableOpacity>
        <TouchableOpacity style={[
          styles.blueB,
          this.state.blueB]} 
          onPress={this.state.canPress ? (()=> this.playerTurn(3)) : null}></TouchableOpacity>
        <TouchableOpacity style={[
          styles.redB,
          this.state.redB]} 
          onPress={this.state.canPress ? (()=> this.playerTurn(4)) : null}></TouchableOpacity>

          <Image
            source={{
              uri: 'https://images-eu.ssl-images-amazon.com/images/I/71pyavpLdIL.png'}}
            style={styles.icon}/>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  greenB:{
    padding: 5,
    height: 80,
    width: 80,  
    borderRadius:160,    
    position: 'absolute',
    top:380,
    left: 110
  },
  yellowB:{
    padding: 5,
    height: 80,
    width: 80,  
    borderRadius:160,   
    position: 'absolute',
    left: 110,
    top: 480

  },
  blueB:{
    padding: 5,
    height: 80,
    width: 80,  
    borderRadius:160,   
    position: 'absolute',
    top: 380,
    left: 210

  },
  redB:{
    padding: 5,
    height: 80,
    width: 80,  
    borderRadius:160, 
    position: 'absolute',
    left: 210,
    top: 480

  },
  playB:{
    padding: 10,
    marginLeft: 155,
    marginTop: 300,
    width: 100,
    backgroundColor: 'grey',
    height: 40,
    borderRadius: 40,
  },
  icon: {
    width: 200,
    height: 200,
    position: 'absolute',
    top: 50,
    left: 100, 
  }
});

Solution

  • Instead using canPress state, you should set a count state, every time the button is clicked, increase count with 1, and use count to compare with seq.length, and then pass the result to the disabled property, like this <button disabled={count === seq.length}>.

    You can check the demo on Codesandbox.

    Edit unruffled-black-pt8ie

    Also maybe This one can give you some ideas about loop functions as a component child. https://reactjs.org/docs/jsx-in-depth.html

    The code below is from React Docs

    // Calls the children callback numTimes to produce a repeated component
    function Repeat(props) {
      let items = [];
      for (let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
      }
      return <div>{items}</div>;
    }
    
    function ListOfTenThings() {
      return (
        <Repeat numTimes={10}>
          {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
      );
    }
    

    You can wrap you TouchableOpacity into a component like Repeat above, then every time player start a new turn, then pass updated turn value as a prop to TouchableOpacity.