1

I’m having problems with a memory game. The way it works is that you are presented with a number of buttons that can “light up”. The buttons light up in a certain sequence, then the user has to press them in the same sequence. I’ve managed to create the layout programmatically. At the moment the following happens:

1: layout is created programmatically, each button in the layout has their text set to a number

2: A sequence of numbers is displayed to the user in a dialog box.

3: The user presses the corresponding buttons and the app checks they are correct.

Instead of having to dislay the dialog box with the sequence in it I want the buttons to “play” the sequence by “lighting up” in a certain order (so eventually I want to change the background image of the buttons but at the moment I'm just trying to change the text).

I’ve already found this thread but haven’t been able to fix the problem.

At the moment the code looks like this but it isn’t working properly at at all, everything works except the code below, which for some reason sets the text of three buttons to "On" all at once (even if the sequence is made up of four different numbers):

    pattern.clear();
// generate a sequence and “play” the sequence to the user
for(int i =0; i<sequenceLength;i++){
  int x = r.nextInt(numButtons);
  pattern.add(x);
  Button b = ((Button)findViewById(x));
  final Button fb = b;
  final Handler h = new Handler();
  Timer t = new Timer();
  t.schedule(new TimerTask(){
    public void run(){
      h.post(new Runnable(){
        public void run(){
          fb.setText(“On”);
        }
      });
    }
  }, 1500);
}

Here is the complete activity file:

    package com.kate.buttonlogic3;

import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends Activity implements OnClickListener {

    int sequenceLength = 4;
    int numButtons = 8;
    int lives = 4;
    int patternPosition = 0;

    //Two ArrayLists for pattern to guess and user guess
    ArrayList<Integer> pattern = new ArrayList<Integer>();
    ArrayList<Integer> userGuess = new ArrayList<Integer>();

    //random num generator
    Random r = new Random();

    //create an array of buttons that will be added to the layout
    Button[] buttons = new Button[numButtons];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // generate a new pattern
        pattern.clear();
        // also want a string version of the pattern that can be printed out to the user
        StringBuilder patternString = new StringBuilder();
        for(int i =0; i<sequenceLength;i++){
            int x = r.nextInt(numButtons);
            pattern.add(x);
            patternString.append(Integer.toString(x));
        }

        // display the pattern to the user
        String message = "The pattern is: " + patternString;
        alert("The Pattern", message);

        // start generating the layout 
        LinearLayout mainLayout = ((LinearLayout)findViewById(R.id.mainLayout));

        /*
         * The layout will be made up of rows of two buttons side-by-side
         * so if there are 6 buttons then there will be 3 rows
         * if there are 5 buttons there will also be 3 rows, the last row will only have one button
         * */

        // based on the number of buttons figure out how many rows are needed
        int numRows = numButtons/2;
        // if there is an odd number of buttons we need an extra row and set odd == true
        boolean odd = false;
        if (numButtons%2 != 0){
            numRows++;
            odd=true;
        }

        // The buttons will have different background colours
        int[] colours = {0xff0000ff, 0xff00ffff, 0xff888888, 0xff00ff00, 0xffff0000, 0xffffff00, 0xffcccccc, 0xffff00ff};


        // each "row" talked about above is actually a linearLayout
        LinearLayout[] rows = new LinearLayout[numRows];

        // create a set of default linearLayout parameters to be given to every linearLayout 
        LayoutParams llParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);

        // add the buttons to each linearLayout row
        // each button created will be given a unique number starting at 0
        int buttonNum = 0;
        for(int i=0; i<numRows; i++){   
            rows[i] = new LinearLayout(this);
            // set parameters for the current linearLayout row
            rows[i].setOrientation(LinearLayout.HORIZONTAL);
            rows[i].setLayoutParams(llParams);  
            // if we've reached the last linearLayout row and there is an odd number of buttons, add only one button
            if( i==(numRows-1) && odd){
                Button btn = new Button(this);
                btn.setText(Integer.toString(buttonNum));
                btn.setId(buttonNum);
                // buttonNum is a unique number for the current button
                // use buttonNum as an index to extract a colour from the colours array
                btn.setBackgroundColor(colours[buttonNum]);
                btn.setOnClickListener(this);
                rows[i].addView(btn);
                // every time we add a button buttonNum is increased
                buttonNum++;
            } 
            // otherwise add two buttons to the current linearLayout row
            else {
                Button[] rowButtons = new Button[2];
                for(Button btn: rowButtons){
                    btn = new Button(this);
                    btn.setText(Integer.toString(buttonNum));
                    btn.setId(buttonNum);
                    // buttonNum is a unique number for the current button
                    // use buttonNum as an index to extract a colour from the colours array
                    btn.setBackgroundColor(colours[buttonNum]);
                    btn.setOnClickListener(this);
                    rows[i].addView(btn);
                    buttonNum++;
                }
            }   
            mainLayout.addView(rows[i]);
        }
        // finish generating the layout 
        pattern.clear();
        // generate a sequence and display the sequence to the user
        for(int i=0; i<sequenceLength;i++){
          int x = r.nextInt(numButtons);
          pattern.add(x);
          Button b = ((Button)findViewById(x));
          final Button fb = b;
          final Handler h = new Handler();
          Timer t = new Timer();
          t.schedule(new TimerTask(){
            public void run(){
              h.post(new Runnable(){
                public void run(){
                  fb.setText("Rest");
                }
              });
            }
          }, 1500);
        }
    }

    @Override
    public void onClick(View v) {
        // get the user's guess i.e. the number of the button that the user has clicked
        int userGuess = v.getId();
        // if the current number in the pattern sequence equals the current userGuess
        if(userGuess==pattern.get(patternPosition)){
            // if we have reached the end of the pattern sequence then the user has guessed the complete sequence correctly
            if(patternPosition==(pattern.size()-1)){
                // restart this activity again so new pattern is generated for the user to guess
                Intent i = getIntent();
                finish();
                startActivity(i);
            }
            // otherwise move on to the next item in the pattern sequence
            patternPosition++;
        }
        // if the user incorrectly guesses the current item in the pattern sequence 
        else{
            // reduce lives
            lives--;
            if(lives==0){
                // start game over activity
            }
            // display the number of lives left to the user
            String message = Integer.toString(lives) + " lives left.";
            alert("Nope", message);
            // keep the current pattern sequence but start the user guess from the beginning
            patternPosition = 0;
        }

    }

    public void alert(String title, String message){
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle(title)
        .setMessage(message)
        .setCancelable(false)
        .setPositiveButton("OK",new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
            }
        });
        AlertDialog alert = builder.create();
        alert.show();   
    }

}

Thanks very much for you help Adam, got it working, here's the code:

        final Timer t = new Timer();
    long timeBetweenChangesMs = 1500;
    long delay = timeBetweenChangesMs;
    for(int i = 0; i < sequenceLength;i++){
        final Button b = ((Button)findViewById(pattern.get(i)));
        final String bNum = String.valueOf(pattern.get(i));
        final Handler h = new Handler();
        delay += timeBetweenChangesMs;
        t.schedule(new TimerTask(){
            public void run(){
                h.post(new Runnable(){
                    public void run(){
                        b.setText("x");
                    }
                });
            }
        }, delay);
        delay += timeBetweenChangesMs;
        t.schedule(new TimerTask(){
            public void run(){
                h.post(new Runnable(){
                    public void run(){
                        b.setText(bNum);
                    }
                });
            }
        }, (delay));
    }
4

1 回答 1

0

您正在同时开始所有任务(或几乎同时开始)。这意味着它们都会您进入循环后 1500 毫秒发生。

您需要做的是增加循环的每次迭代的延迟时间。像这样的东西会起作用:

Timer t = new Timer();
long timeBetweenChangesMs = 1500;
for(int i = 0; i < sequenceLength;i++){
  int x = r.nextInt(numButtons);
  pattern.add(x);
  final Button b = ((Button)findViewById(x));
  final Handler h = new Handler();
  long delay = timeBetweenChangesMs + timeBetweenChangesMs * i;
  t.schedule(new TimerTask(){
    public void run(){
      h.post(new Runnable(){
        public void run(){
          fb.setText(“On”);
        }
      });
    }
  }, 1500);
}

至于为什么只有 3 个发生变化 - 我怀疑这是因为当您获得下一个按钮的随机 ID 时,您没有跟踪已经更新的按钮 ID。因此,您只需在同一个按钮上设置“开”两次。您可以检查您是否pattern已经包含下一个按钮的 ID ( x);在此期间,请继续获取新的随机 ID。

于 2013-11-14T00:13:55.217 回答