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));
}