I need to save 5 best times (an integer) for a game. The game is a reaction time game.
I'm assuming that the easiest way to do this would be to store it in a text file but I really have no idea how to go about doing this.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button) findViewById(R.id.btnStart);
textTimer = (TextView) findViewById(R.id.textTimer);
myHandler = new Handler();
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
startTime = SystemClock.uptimeMillis();
myHandler.postDelayed(updateTimerMethod, 0);
MainActivity.this.textTimer.setVisibility(0);
}
});
pauseButton = (Button) findViewById(R.id.btnPause);
pauseButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
timeSwap += timeInMillies;
myHandler.removeCallbacks(updateTimerMethod);
MainActivity.this.textTimer.setVisibility(0);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private Runnable updateTimerMethod = new Runnable() {
#Override
public void run() {
timeInMillies = SystemClock.uptimeMillis() - startTime;
finalTime = timeSwap + timeInMillies;
int seconds = (int) (finalTime / 1000);
int minutes = seconds / 60;
seconds = seconds % 60;
int milliseconds = (int) (finalTime % 1000);
textTimer.setText("" + minutes + ":" + String.format("%02d", seconds) + ":" + String.format("%03d", milliseconds));
myHandler.postDelayed(this, 0);
}
};
that is the code i have for now. all i want to happen is that when i press the pause button, it will go to the next screen and display the time. and also there will be a button, let's say "records". if it is pressed, it will display the 5 best times.
Instead of using a file to save scores, you can use SharedPreferences putInt() and getInt() methods to save int values.
The following sample is a possible (very lazy) implementation of it;
protected final static String PREFS_NAME = "PREF_GAME_SCORE";
public static int GetBestScore(Context context, int no)
{
SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
return settings.getInt("Score" + String.valueOf(no), 0); // # 0 is the default value if no data is found
}
public static void SetBestScore(Context context, int no, int score)
{
SharedPreferences settings = context.getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("Score" + String.valueOf(no), score);
editor.commit();
}
You can use SetBestScore(conxtext, 1, 666); to set the best score #number:1 and to get the best score, use; GetBestScore(context, 1);
The values saved using SharedPreferences will remain until the application is removed from the device or Application Data is cleared manually using:
Settings -> Applications -> Manage applications -> (choose your app)
-> Clear data
Building off of what Zefnus said, here is a method to send a score in and check if it is in the top lowest scores. If it is, it sets the TEMP_SPOT and then updates accordingly.
You could set any number of top scores too. This could easily be modified to got the other way too, IE, check for high scores.
public static void CheckAndSetBestScore(Context context, int score) {
int TOTAL_TOP_SCORES = 5;
int TEMP_SPOT = -1;
SharedPreferences settings = context
.getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
for (int i = 1; i <= TOTAL_TOP_SCORES; ++i) {
if (TEMP_SPOT == -1) {
if (score <= settings.getInt("Score" + String.valueOf(i), 1000)) {
TEMP_SPOT = i;
}
}
}
if (TEMP_SPOT != -1) {
for (int i = TOTAL_TOP_SCORES; i >= TEMP_SPOT; --i) {
if (i != TEMP_SPOT) {
editor.putInt("Score" + String.valueOf(i), settings.getInt("Score" + String.valueOf(i - 1), 1000));
}
else {
editor.putInt("Score" + String.valueOf(i), score);
}
}
}
}
There are three ways to do it
1. Flat FIle
2. Shared Preferences
3. SQL
Personally i would recommend you to go for SQL, since any of the operation that you want to add in the future makes lesser work.If in case of sharedpreferences you need a whole new set of code to handle a new operation.so better go with sqlite.
Whenever a game is ended take the score and insert it to the table. When you want to display the top 5 results. Do a query with Score in Ascending order and limit to 5 rows. Bingo you can get the result,which you wanted.
Hope it helps.
Take a look at this link for how to create and use an SQL database from android.
http://chrisrisner.com/31-Days-of-Android--Day-24%E2%80%93Using-SQLite-Databases
Related
I have a working app where images are being downloaded from the server, stored locally and being displayed in an image view as a slideshow every few seconds. I would like to count how many times each images is being displayed. I'm unsure how to tackle this. Should I make 6 counters (one for each image) or should I create an array to store the image name and count? But how do I update it?
Any assistance or code snippets would be much appreciated.
protected void onPostExecute(String s) {
super.onPostExecute(s);
imageView = findViewById(R.id.imgholder);
Timer mTimer = new Timer();
mTimer.schedule(new TimerTask() {
#Override
public void run() {
// As timer is not a Main/UI thread need to do all UI task on runOnUiThread
DashboardActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// increase your position so new image will show
position++;
// check whether position increased to length then set it to 0
// so it will show images in circuler
if (position >= 6)
position = 0;
File file = new File(Environment.getExternalStorageDirectory(), user.fullName + "-" + position + ".jpg");
imgUri = Uri.fromFile(file);
Log.v("test", "Now Showing Image: " + imgUri.toString());
// Set Image
imageView.setImageURI(imgUri);
counter++;
Log.v("test","Image: "+ position +" has appeared: " +counter);
}
});
}
}, 0, DELAY_TIMER);
Create an integer array of length 6 int[] counters = new int[]{0,0,0,0,0}, Then after if(position >= 6) position = 0; in your code , increment the counter as counters[position]++;. So you can always track the count of image at certain position from the array counters
Create a HashMap to store the count
private HashMap<String, Integer> countMap = new HashMap<>();
now whenever you set an image call below method:
private void updateDisplayCount(File file) {
if(countMap.containsKey(file.getName())) {
countMap.put(file.getName(), countMap.get(file.getName()) + 1);
} else {
countMap.put(file.getName(), 1);
}
}
The following code will return the display count
int count = countMap.get(file.getName())
I am making game in which i want to set that a user can only play game in a days 3 time..
When he played 3 times in a days then a message will pop up that you have reached to your limit and can not play more..
Try below code, explanations are inside code:
public class MainActivity extends AppCompatActivity {
private int lastCheck = 0;
private SharedPreferences pref;
private SharedPreferences.Editor editor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
pref = getApplicationContext().getSharedPreferences("MyPref", 0);
editor = pref.edit();
//GET THE LAST CHECKED DATE FROM SHARED PREFERENCES, WE ARE USING DAY OF A MONTH
lastCheck = pref.getInt("lastcheck", 0);
//GET THE NUMBER OF TIMES THE ACTIVITY WAS OPENED FROM SHARED PREFERENCES
int count = pref.getInt("count", 0);
// IF IT IS A NEW DAY START COUNTING FROM 0 AGAIN
if(isNewDay()){
count = 0;
}
// IF COUNT REACHES 5 CLOSE THE ACTIVITY. YOU CAN USE ANY OTHER MEANS TO BLOCK IT.
if (count >= 5){
finish();
}
else{
// ELSE INCREMENT COUNT AND SAVE IT IN THE SHARED PREFERENCES
count++;
editor.putInt("count", count);
editor.commit();
}
}
// GET THE CURRENT DAY IN THE MONTH AND COMPARE IT WITH THE LAST CHECKED
public boolean isNewDay() {
Date date = new Date();
int today = Integer.parseInt(DateFormat.format("dd", date).toString());
boolean ret = lastCheck == 0 || today > lastCheck;
lastCheck = today;
return ret;
}
}
private fun isNewDay(): Boolean {
val date = Date()
val today: Int = DateFormat.format("dd", date).toString().toInt()
val ret = lastCheck == 0 || today > lastCheck
lastCheck = today
sharedPreferenceHandler.setAlbumCreatedDate(lastCheck)
return ret
}
if(isNewDay()){
//do what you want
}
I'm trying to make the second sound on this app. oscillate in volume based on a Sin curve as a function of time passing. How would you suggest I edit what I already have to make that work? Any help would be amazing!
I'm sorry If some of the code is bad, I stepped away from this for some time and I added some sections back in that I previously commented out. I wasn't sure if it was for a good reason or not, so I added it back in.
MediaPlayer beep;
MediaPlayer sound2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //call superclass onCreate
setContentView(R.layout.activity_main); //inflate the GUI
minutesChanged = (TextView) findViewById(R.id.minutesChanged);
secondsChanged = (TextView) findViewById(R.id.secondsChanged);
minutesTotal = (TextView) findViewById(R.id.totalMinutesEntered);
secondsTotal = (TextView) findViewById(R.id.totalSecondsEntered);
percentageFinishedAmount = (TextView) findViewById(R.id.percentageFinishedAmount);
errorMessage = (TextView) findViewById(R.id.errorMessage);
secondEditText =
(EditText) findViewById(R.id.secondEditText);
secondEditText.addTextChangedListener(secondEditTextWatcher);
minuteEditText =
(EditText) findViewById(R.id.minuteEditText);
minuteEditText.addTextChangedListener(minuteEditTextWatcher);
whichSound =
(EditText) findViewById(R.id.whichSound);
whichSound.addTextChangedListener(whichSoundTextWatcher);
seekBarSeconds =
(SeekBar) findViewById(R.id.seekBarSeconds);
seekBarSeconds.setOnSeekBarChangeListener(seekBarListener);
seekBarMinutes =
(SeekBar) findViewById(R.id.seekBarMinutes);
seekBarMinutes.setOnSeekBarChangeListener(seekBarListener);
percentSeekBar =
(SeekBar) findViewById(R.id.seekBarTotal);
beep = MediaPlayer.create(MainActivity.this, R.raw.beep);
sound2 = MediaPlayer.create(MainActivity.this, R.raw.sound);
}
private void calculate() {
totalmili = minutesT + secondsT;
new CountDownTimer(totalmili + 2000, interv) {
public void onTick(long millisUntilFinished) {
secondsEllapsed = (int) ((totalmili + 2000 - millisUntilFinished) / 1000);
minutesEllapsed = secondsEllapsed / 60;
secondsEllapsed = secondsEllapsed % 60;
totalTimeEllapsed = secondsEllapsed + (minutesEllapsed * 60);
Log.d("Lucas", "total time elapsed " + totalTimeEllapsed);
if (totalTimeEllapsed < 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : 0" + secondsEllapsed);
} else if (totalTimeEllapsed >= 10) {
errorMessage.setText("Elapsed Time: " + minutesEllapsed + " : " + secondsEllapsed);
}
//set seekBar minutes/seconds and changing minute/seconds textView
seekBarMinutes.setProgress(minutesEllapsed);
minutesChanged.setText(Integer.toString(minutesEllapsed));
seekBarSeconds.setProgress(secondsEllapsed);
secondsChanged.setText(Integer.toString(secondsEllapsed));
double t = sin((360/totalmili) *(totalTimeEllapsed*1000));
float left = (float) ((t+1.0)*0.9/2.0+0.1);
float right = (float) ((t+1.0)*0.9/2.0+0.1);
sound2.setVolume(left,right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
if(sound == 1){
musicPlaying = beep.isPlaying();
if(musicPlaying == true){
beep.pause();
beep.seekTo(0);
beep.start();
} else {
beep.start();
}
}else if (sound == 2){
if(start ==1) {
sound2.seekTo(19);
sound2.start();
start = 2;
float left = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
float right = (float) ((sin(totalTimeEllapsed)+1.0)*0.9/2.0+0.1);
sound2.setVolume(left, right);
Log.d("Lucas", "value of left and red respectively " + left + ", " +right);
musicPlaying = sound2.isPlaying();
}else if(start ==2){
if (totalTimeEllapsed == 11) {
sound2.pause();
sound2.seekTo(34);
sound2.start();
} else if (totalTimeEllapsed == 22) {
sound2.pause();
}
}
//calculate total percentage finished, set percentage text, set total percentage seekBar
int percentProgress = (int) Math.round(((double) totalTimeEllapsed) / ((double) (totalmili) / 1000) * 100);
percentageFinishedAmount.setText(percentProgress + "% ");
percentSeekBar.setProgress(percentProgress);
//change background and text color bassed on increasing progress
errorMessage.setBackgroundColor(Color.argb(255, (int) (percentProgress * 2.5), 0, 0));
errorMessage.setTextColor(Color.argb(255, (int) (255 - (percentProgress * 2.5)), 255, 255));
}
public void onFinish() {
//display on finish text
errorMessage.setText("Done!");
}
}.start();
}
//listener object for the EditText's text-changed events
private final TextWatcher minuteEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set hours Total and converts minutes to milliseconds
if (s.charAt(start + count - 1) == '\n') {
minuteEditText.getText().replace(start + count - 1, start + count, " ");
s = minuteEditText.getText();
Log.d("Lucas", "in enter key min, s = " + s);
try {
minutesT = Integer.parseInt(s.toString());
minutesTotal.setText(String.valueOf(minutesT) + " Minutes");
percentageFinishedAmount.setText(" ");
minutesT *= 60000;
} catch (NumberFormatException e) {
minutesTotal.setText("");
minutesT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
// listener object for the EditText's text-changed events
private final TextWatcher secondEditTextWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// set minutes Total when text is changed, calls calculate, changes seconds to milliseconds
if (s.charAt(start + count - 1) == '\n') {
secondEditText.getText().replace(start + count - 1, start + count, " ");
s = secondEditText.getText();
Log.d("Lucas", "in enter key sec, s = " + s);
try {
secondsT = Integer.parseInt(s.toString());
secondsTotal.setText(String.valueOf(secondsT) + " Seconds");
secondsT *= 1000;
percentageFinishedAmount.setText(" ");
calculate();
} catch (NumberFormatException e) {
secondsTotal.setText("");
secondsT = 0;
}
}
}
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
};
Yowza. I'm not really clear on what the requirements are here or what you are doing.
My approach would be radically different, and maybe missing the point of what you are attempting. It would have these elements:
1) Output via a SourceDataLine, as this gives you a handle to affect the volume of every frame.
2) Per frame, consult a pointer into a Sin LUT that has the same number of elements as needed to correspond to the desired rate. (But it could also be fine to just create an argument into a sine function that increments the correct amount each frame to get your desired rate. No need to get into a war about whether the function or the LUT performs better.)
3) Multiply the SDL frame by the Sin LUT value.
For example an LFO of 1 Hz would imply either an LUT of 44100 elements, or an argument that increments by 1/44100 per frame.
As for getting access to the individual sound frames, see the tutorial Using Files and Format Converters/Reading Sound Files and look for the point in the example with the comment "Here, do something useful with the audio data that's now in the audioBytes array". That useful thing would be to convert the bytes to PCM (there are other StackOverflow explain how), get your next sin function value and multiply, then convert back to bytes.
EDIT:
Looking into the MediaPlayer API, I'm not clear you will be able to efficiently do what you want with this class.
A player is not prepared to respond to commands quasi-immediately
until its status has transitioned to MediaPlayer.Status.READY, which
in effect generally occurs when media pre-roll completes.
Does this imply some sort of buffer-size that will limit the frequency at which you can make the volume updates? IDK. When we get into buffer-size issues that in effect enforce a maximum number of updates per second, one has to listen carefully to check that there are no clicks or zippering due to discontinuities when the volume jumps from one level to another. A lot also depends on the amount of overhead happening under the hood when you set the position for each volume change.
With a SourceDataLine output, you have clean access to each frame which pretty much eliminates the potential zippering problems. I should add disclaimer though that I haven't grappled with MediaPlayer and may be ignorant of capabilities that you can take advantage of. Regardless, SDL is low level, powerful and efficient.
How can I get to iterate through this ArrayList algorithm so that I can change the background of an imageView every time I input a code... E.g. Code = "123456" | Background_1 shows, Code = "123456" | Background_2 shows ...
enter = (ImageButton) findViewById(R.id.enter);
input = (EditText) findViewById(R.id.editText2);
punch_back_1 = (ImageView) findViewById(R.id.imageView6);
punch_back_2 = (ImageView) findViewById(R.id.imageView7);
punch_back_3 = (ImageView) findViewById(R.id.imageView8);
punch_back_4 = (ImageView) findViewById(R.id.imageView9);
final ArrayList<ImageView> array_image = new ArrayList<>();
array_image.add(punch_back_1);
array_image.add(punch_back_2);
array_image.add(punch_back_3);
array_image.add(punch_back_4);
enter.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
String code = input.getText().toString();
int i = 0;
if (code.equals("123456")) {
i++;
array_image.get(i).setImageResource(R.drawable.punch_front);
Toast.makeText(getApplication(), "Awarded 1 new punch", Toast.LENGTH_LONG).show();
}
} else if (event.getAction() == MotionEvent.ACTION_UP) {
input.setText(" ");
}
return false;
}
});
I've tried this both:
for (int i = 0; i < 4; i++)
{
if (code.equals("123456"))
{
array_image.get(i).setImageResource(R.drawable.punch_front);
Toast.makeText(getApplication(), "Awarded 1 new punch", Toast.LENGTH_LONG).show();
}
}
int i = 0;
while (i < i)
{
array_image.get(i).setImageResource(R.drawable.punch_front);
Toast.makeText(getApplication(), "Awarded 1 new punch", Toast.LENGTH_LONG).show();
i++;
}
Which, if I am not mistaken does the same thing.
The below line of code eventually worked for me. onTouch Action_UP was my culprit. Using input.setText(null); did the same effect I wanted and preserved my sanity...
enter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String code = input.getText().toString();
if (code.equals("123456") && index < array_image.size()) {
array_image.get(index).setImageResource(R.drawable.punch_front);
index++;
Toast.makeText(getApplication(), "Awarded " + index + " new punch", Toast.LENGTH_LONG).show();
input.setText(null);
}
}
});
EDIT: I seem to have misunderstood your question. It looks as if you want to have the image appear only once per fire event.
Doing this would require you do two things.
Keep count of the index at which you'll be changing.
Increment the index after use.
Also, you'll need to insure you do not go out of bounds as well of course.
First create a counter for the index as a member.
private int index = 0;
Next you'll want to do what you were doing before almost. In your event listener:
if(code.equals("123456") && index < array_image.size())
{
array_image.get(index).setImageResource(R.drawable.punch_front);
index++;
}
This should keep track of the current index, increment its position for the next event, and after you've gone through your items in the array, it shouldn't give you any exception errors when you go out of bounds and try to fire the event again.
Thanks for all suggestion and thoughts i finally achieved it by yours suggestions and it was a simple logic work to solve the problem. I want to share it if any one want to create custom Health Bar , but it is not suitable for 100 HP because then you have to write 100 IF statements,
Idea was to create simple custom Healthbar and decrease it by pressing button clicks.
This link also help me a lot.
HealthBar
Code
private TextView Message,result;
private Button play;
private float maxHP = 10;
private float currentHP = maxHP;
//private float percentHP = (float) (currentHP/maxHP);
private int user_shield;
private float healthBar;
private ImageView shieldusb1,shieldusb2,shieldusb3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level_one);
Initialize();
}
private void Initialize(){
user_shield = R.raw.shield_blue;
shieldusb2 = (ImageView) findViewById(R.id.shield_b2);
shieldusb1 = (ImageView) findViewById(R.id.shield_b1);
shieldusb3 = (ImageView) findViewById(R.id.shield_b3);
result = (TextView) findViewById(R.id.result);
play = (Button) findViewById(R.id.playButton);
play.setOnClickListener(new OnClickListener(){
public void onClick(View arg0){
play();
}
});
}
public void play(){
{
healthBar=0;
currentHP = (float) (currentHP - 0.5);
//currentHP -= 1;
if(currentHP <= 0) //if the player died
{
currentHP = 0; //set his HP to zero, (just in case)
Message.setText("You died! :P"); //add any extra death-code here
//update the healthBar
result.setText ("WIN POINTS");
}
updateHealthBar();
}
}
private void updateHealthBar() {
// percentHP = currentHP / maxHP;
healthBar = currentHP;
if(healthBar<9.6){
shieldusb1.setVisibility(View.GONE);
}
{
if (healthBar<=9){
shieldusb2.setVisibility(View.GONE);
}
if (healthBar<=8.6){
shieldusb3.setVisibility(View.GONE);
}
}
}
My guess, is you need to remove the else if and make it just if because if you execute first statement where <= 1, else if will never get executed.
private void updateHealthBar() {
percentHP = currentHP / maxHP; / calculating points
healthBar = percentHP;
if(healthBar<=1){ // Hiding first Image View
shieldusb1.setVisibility(View.GONE);
}
if (healthBar<=0.9){
shieldusb2.setVisibility(View.GONE); // How to Hide this Image View after button click
}
}
Your healthBar is of int type, so checking against 0.9 is the same as checking against 1.
Also, in your conditions, you're first checking:
if (healthBar <= 1)
If this condition is true, you're hiding shieldusb1, and you will never reach second condition because you have used else. What you can do is to remove else in front of second condition, but as said above, your healthBar is int, so the second condition is basically the same as the first. Change healthBar to double.
You need to adjust these conditions
if(healthBar<=1)
...
else if (healthBar<=0.9)
Even if healthBar<= 0.9 evaluates true, healthBar<=1 is also true so it will always enter the first if
You check if healthBar is <= 1, and after if is <= 0.9... But this case never verify, cause 0.9 is < 1, so it always choose the first option!
Change your first if for check values between 1 and 0.9, and it will work!
It's only logical problem. Change if/else if block for if/if.
if(healthBar<=1)
shieldusb1.setVisibility(View.GONE);
if (healthBar<=0.9)
shieldusb2.setVisibility(View.GONE);