I have a problem closing my game after the last player close the last match. My turn scheme is:
Player A
Player B
Player B
Player A
Player A
Player B
The game works well but in turn "6" when player B try to close the match, player A always see the matsh as "my turn" and not as "completed"
here there is the code thar rules turns and game ended:
#Override
public void onGameEnd(final NMXGameData updatedData) {
super.onGameEnd(updatedData);
if (updatedData.getMatchNumber() == NMXGameConfig.MATCHES) {
boolean iWin = updatedData.getResultPoints()[1] > updatedData.getResultPoints()[0];
boolean tile = updatedData.getResultPoints()[1] == updatedData.getResultPoints()[0];
ParticipantResult opponentParticipantResult;
ParticipantResult myParticipantResult;
if (tile) {
opponentParticipantResult = new ParticipantResult(getOpponentId(), ParticipantResult.MATCH_RESULT_TIE, 1);
myParticipantResult = new ParticipantResult(getCurrentPlayerId(), ParticipantResult.MATCH_RESULT_TIE, 1);
} else {
if (iWin) {
opponentParticipantResult = new ParticipantResult(getOpponentId(), ParticipantResult.MATCH_RESULT_LOSS, 2);
myParticipantResult = new ParticipantResult(getCurrentPlayerId(), ParticipantResult.MATCH_RESULT_WIN, 1);
} else {
opponentParticipantResult = new ParticipantResult(getOpponentId(), ParticipantResult.MATCH_RESULT_WIN, 1);
myParticipantResult = new ParticipantResult(getCurrentPlayerId(), ParticipantResult.MATCH_RESULT_LOSS, 2);
}
}
ArrayList<ParticipantResult> participantResultArrayList = new ArrayList<>();
participantResultArrayList.add(opponentParticipantResult);
participantResultArrayList.add(myParticipantResult);
Games.TurnBasedMultiplayer.finishMatch(getApiClient(), match.getMatchId(), new Gson().toJson(updatedData).getBytes(), opponentParticipantResult, myParticipantResult).setResultCallback(new ResultCallback<TurnBasedMultiplayer.UpdateMatchResult>() {
#Override
public void onResult(TurnBasedMultiplayer.UpdateMatchResult updateMatchResult) {
finish();
}
});
} else if (updatedData.getMatchNumber() < NMXGameConfig.MATCHES) {
if (getNextPlayerIndex(updatedData.getMatchNumber()) != getNextPlayerIndex(updatedData.getMatchNumber() - 1)) {
Games.TurnBasedMultiplayer.takeTurn(getApiClient(), match.getMatchId(), new Gson().toJson(updatedData).getBytes(), getNextParticipantId());
} else {
Games.TurnBasedMultiplayer.takeTurn(getApiClient(), match.getMatchId(), new Gson().toJson(updatedData).getBytes(), getCurrentPlayerId());
startActivity(startNewOnlineGameIntent(this, updatedData, match.getMatchId()));
}
finish();
}
}
private String getCurrentPlayerId() {
return match.getParticipantId(Games.Players.getCurrentPlayerId(getApiClient()));
}
private String getOpponentId() {
for (String id : match.getParticipantIds()) {
if (!id.equals(getCurrentPlayerId())) {
return id;
}
}
return null;
}
private int getNextPlayerIndex(int nextRoundIndex) {
nextRoundIndex = nextRoundIndex + 1;
return (nextRoundIndex / 2) % 2;
}
I finally figured it out.
I don't know if that is the desired behavior but when in round 6 player_B calls:
Games.TurnBasedMultiplayer.finishMatch(getApiClient(), match.getMatchId(), new Gson().toJson(updatedData).getBytes(), opponentParticipantResult, myParticipantResult).setResultCallback(new ResultCallback<TurnBasedMultiplayer.UpdateMatchResult>() {
#Override
public void onResult(TurnBasedMultiplayer.UpdateMatchResult updateMatchResult) {
finish();
}
});
The turn goes to player_A that see that match as "my turn". At this point player A must call Games.TurnBasedMultiplayer.finishMatch(getApiClient(), match.getMatchId()) (without playing a real game) and the game is completed for both players
Related
I want to add pause and play functionality in tts. what is have done so far is, when i stop tts speaking and want to get the last spoken word but the loop which is running not getting stop. please resolve my problem.
public void toggleAudioMode() {
isPlayerVisible = !isPlayerVisible;
ivToggleAudioModeAnswer.setImageResource(isPlayerVisible ? R.drawable.ic_audio_off : R.drawable.ic_audio_on);
if (isPlayerVisible) {
splitspeech = result.split(" ");
if (j > 0) {
speakSpeech(j, "run");
} else {
speakSpeech(0, "run");
}
} else {
keepGoing = false;
speakSpeech(0, "stop");
}
}
public void speakSpeech(int m, String type) {
myHash.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "done");
while (i < splitspeech.length) {
if (type.equals("run")) {
if (i == 0) { // Use for the first splited text to flush on audio stream
textToSpeech.speak(splitspeech[i].trim(), QUEUE_FLUSH, myHash);
} else { // add the new text on previous then play the TTS
textToSpeech.speak(splitspeech[i].trim(), QUEUE_ADD, myHash);
j = i;
}
}
i++;
}
if (type.equals("stop")) {
textToSpeech.stop();
}
}
i want play and pause functionality.
I am creating a class witch loads up a few sounds. However, isPlaying keeps on throwing an exception after a while and then stops playing that particular sound permanently, while other sounds keep playing OK.
public class MySound {
int m_IdMyId;
int m_ResId;
boolean m_IsLoaded;
MediaPlayer m_Media;
public MySound(int idMyId, int resId){
m_IdMyId = idMyId;
m_ResId = resId;
m_IsLoaded = false;
m_Media = null;
}
}
In this m_IdMyId is just an id for my game. m_ResId is something like R.raw.mysound1. m_IsLoaded I think is automatically set to true as I am loading synconously. m_Media is the MediaPlayer object.
I am calling stop() very regularly, as it is a game and I need to check every second or so to make sure certain sounds are stopped. It is here that it throws an exception when snd.m_Media.isPlaying() is called.
I cannot seem to access e to see what the error is.
Also I would like to know how I can set m_IsLoaded correctly. How do I know when the sound is fully loaded and ready to use?
Here is my management class:
public class MySoundManager {
MainActivity m_Context;
ArrayList<MySound> mySounds;
public MySoundManager(MainActivity context) {
m_Context = context;
mySounds = new ArrayList<MySound>();
mySounds.add(new MySound(8, R.raw.mysound1));
mySounds.add(new MySound(10, R.raw.mysound2));
mySounds.add(new MySound(22, R.raw.mysound3));
mySounds.add(new MySound(100, R.raw.click));
mySounds.add(new MySound(101, R.raw.error));
for(MySound mysound : mySounds) {
mysound.m_Media = MediaPlayer.create(m_Context, mysound.m_ResId); // no need to call prepare(); create() does that for you
mysound.m_IsLoaded = true;
}
}
// I call this when the main thread calls onResume
public void onResume(){
for(MySound mysound : mySounds) {
if(mysound.m_Media == null) {
mysound.m_Media = MediaPlayer.create(m_Context, mysound.m_ResId); // no need to call prepare(); create() does that for you
mysound.m_IsLoaded = true;
}
}
}
// I call this when the main thread calls onPause
public void onPause(){
for(MySound mysound : mySounds) {
if(mysound.m_Media != null) {
mysound.m_Media.stop();
mysound.m_Media.release();
mysound.m_Media = null;
}
}
}
public boolean IsAllLoaded(){
for(MySound mysound : mySounds) {
if(!mysound.m_IsLoaded) return false;
}
return true;
}
public MySound FindMySoundByIdMyId(int idMyId){
try {
for(MySound mysound : mySounds) {
if (mysound.m_IdMyId == idMyId) return mysound;
}
}catch(Exception e) {
MySound snd;
snd = null; // ToDo
}
return null;
}
public void play(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null)
snd.m_Media.start();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
public void pause(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null &&
snd.m_Media.isPlaying())
snd.m_Media.pause();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
public void pauseAll(){
try{
for (MySound mysound : mySounds) {
if(mysound.m_Media.isPlaying())
mysound.m_Media.pause();
}
}catch(IllegalStateException e) {
MySound snd;
snd = null; // ToDo
}
}
public boolean isPlaying(int idMyId, MySound[] fill){
MySound snd;
fill[0] = null;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null){
fill[0] = snd;
return snd.m_Media.isPlaying();
}
}catch(IllegalStateException e) {
snd = null; // ToDo
}
return false;
}
public void stop(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null &&
snd.m_Media.isPlaying())
snd.m_Media.stop();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
// The str is in the format
// number id, 1 = on 0 = off,dont play if this id playing;
public void PlaySound(String str) {
boolean isplaying;
int i, len, id, idDontPlay, milliNow;
String[] strARR = str.split(";");
String[] strARR2;
Integer[] tmpIntARR;
ArrayList<Integer[]> onARR = new ArrayList<Integer[]>();
ArrayList<Integer> offARR = new ArrayList<Integer>();
MySound snd;
for (i = 0, len = strARR.length; i < len; i++) {
if(strARR[i].length() <= 0) continue;
if((strARR2 = strARR[i].split(",")) != null &&
strARR2.length >= 3 &&
strARR2[0].length() > 0 &&
strARR2[1].length() > 0 &&
strARR2[2].length() > 0){
id = Integer.parseInt(strARR2[0]);
idDontPlay = Integer.parseInt(strARR2[2]);
tmpIntARR = new Integer[2];
tmpIntARR[0] = id;
tmpIntARR[1] = idDontPlay;
if(Integer.parseInt(strARR2[1]) == 1){
onARR.add(tmpIntARR);
} else offARR.add(id);
}
}
// Turn off all sounds that need to be turned off
for (i=0,len=offARR.size();i<len;i++) {
id = offARR.get(i);
stop(id);
}
// Turn all sounds that need to be turned on,
// but only if the sound that blocks a new sound is not playing
for (i=0,len=onARR.size();i<len;i++) {
tmpIntARR = onARR.get(i);
id = tmpIntARR[0];
idDontPlay = tmpIntARR[1];
// We dont play if the idDontPlay sound is already playing
if((snd = FindMySoundByIdMyId(idDontPlay)) != null &&
snd.m_Media.isPlaying())
continue;
if((snd = FindMySoundByIdMyId(id)) != null){
isplaying = snd.m_Media.isPlaying();
milliNow = snd.m_Media.getCurrentPosition();
if(milliNow > (snd.m_Media.getDuration() - 1000) ||
(!isplaying && milliNow > 0)){
snd.m_Media.seekTo(0); // Half a second inside
}
if(!isplaying) snd.m_Media.start();
}
}
}
}
Creating a MediaPlayer instance for every sound is not a good practice to get low latency, especially for short clips. MediaPlayer is for longer clips such as Music files it uses large buffer so, larger buffer means high latency. Also, there is AudioFocus mechanism on Android that may interfere your sound playing session. So, I strongly recommend you to use SoundPool to play short clips like game sounds.
I'm trying to implement a fast-forward and rewind actions using PlaybackControlsRow using Leanback library for Android TV, however I can't find any method to detect a long press on these buttons. My current implementation is simple, only does seeking for 10 seconds on one click:
private void setupRows() {
final ClassPresenterSelector ps = new ClassPresenterSelector();
final PlaybackControlsRowPresenter playbackControlsRowPresenter =
new PlaybackControlsRowPresenter(new DescriptionPresenter());
playbackControlsRowPresenter.setOnActionClickedListener(action -> {
if (action.getId() == playPauseAction.getId()) {
togglePlayback(playPauseAction.getIndex() == PlayPauseAction.PLAY);
} else if (action.getId() == fastForwardAction.getId()) {
fastForward();
return;
} else if (action.getId() == rewindAction.getId()) {
rewind();
return;
}
if (action instanceof PlaybackControlsRow.MultiAction) {
((PlaybackControlsRow.MultiAction) action).nextIndex();
notifyChanged(action);
}
});
ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
rowsAdapter = new ArrayObjectAdapter(ps);
updatePlaybackControlsRow();
setAdapter(rowsAdapter);
}
private void fastForward() {
((PlaybackActivity) getActivity()).onFragmentFastForward();
final int currentTime = ((PlaybackActivity) getActivity()).getPosition();
playbackControlsRow.setCurrentTime(currentTime);
}
private void rewind() {
((PlaybackActivity) getActivity()).onFragmentRewind();
final int currentTime = ((PlaybackActivity) getActivity()).getPosition();
playbackControlsRow.setCurrentTime(currentTime);
}
In PlaybackActivity:
public void onFragmentFastForward() {
// Fast forward 10 seconds.
videoView.seekTo(videoView.getCurrentPosition() + (10 * 1000));
}
public void onFragmentRewind() {
videoView.seekTo(videoView.getCurrentPosition() - (10 * 1000));
}
Is it possible to implement fast-forward and rewind on long press of actions, like key-up/key-down events on the action buttons?
After looking for other solutions, seems that PlaybackControlsRowPresenter is designed in the way that it should have no long presses, but instead increasing/reducing speed by the number of clicks on fast-forward/rewind buttons. It can be clearly seen from internal constructor implementation of PlaybackControlsRowPresenter.FastForwardAction and PlaybackControlsRowPresenter.RewindAction classes:
/**
* Constructor
* #param context Context used for loading resources.
* #param numSpeeds Number of supported fast forward speeds.
*/
public FastForwardAction(Context context, int numSpeeds) {
So, as the result, my solution for now is increasing/reducing a speed by each click on the fast-forward/rewind buttons (which is done on UI by default). After that, when I click on play - it just resumes video from the seeked point.
UPDATE (updated parts of code):
private void setupRows() {
final ClassPresenterSelector ps = new ClassPresenterSelector();
final PlaybackControlsRowPresenter playbackControlsRowPresenter =
new PlaybackControlsRowPresenter(new DescriptionPresenter());
playbackControlsRowPresenter.setOnActionClickedListener(action -> {
if (action.getId() == playPauseAction.getId()) {
togglePlayback(playPauseAction.getIndex() == PlayPauseAction.PLAY);
((PlaybackControlsRow.MultiAction) action).nextIndex();
notifyChanged(action);
} else if (action.getId() == fastForwardAction.getId()) {
if (currentSpeed <= MAX_SPEED) {
currentSpeed++;
showTogglePlayback(false, true);
if (currentSpeed < 0) {
prevRewind();
} else if (currentSpeed > 0) {
nextFastForward();
} else {
currentSpeed++;
prevRewind();
nextFastForward();
}
((PlaybackActivity) getActivity()).seek(currentSpeed);
}
} else if (action.getId() == rewindAction.getId()) {
if (currentSpeed >= MIN_SPEED) {
currentSpeed--;
showTogglePlayback(false, true);
if (currentSpeed > 0) {
prevFastForward();
} else if (currentSpeed < 0) {
nextRewind();
} else {
currentSpeed--;
prevFastForward();
nextRewind();
}
((PlaybackActivity) getActivity()).seek(currentSpeed);
}
} else if (action.getId() == R.id.lb_control_picture_in_picture &&
PlaybackActivity.supportsPictureInPicture(getActivity())) {
getActivity().enterPictureInPictureMode();
}
});
ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
rowsAdapter = new ArrayObjectAdapter(ps);
updatePlaybackControlsRow();
setAdapter(rowsAdapter);
}
private void prevFastForward() {
fastForwardAction.setIndex(fastForwardAction.getIndex() - 1);
notifyChanged(fastForwardAction);
}
private void nextFastForward() {
fastForwardAction.nextIndex();
notifyChanged(fastForwardAction);
}
private void prevRewind() {
rewindAction.setIndex(rewindAction.getIndex() - 1);
notifyChanged(rewindAction);
}
private void nextRewind() {
rewindAction.nextIndex();
notifyChanged(rewindAction);
}
I m facing issue in fitness app after 1 hr timertask runs slow or sometimes it runs too fast like it increase 2 second simantaneously please someone suggest stable solution ..I am saving user history when ever I get new location any help is appreciated
public void reStartTimerTask(final boolean onCreate) {
if (Validator.isNull(timer)) {
if (preferences.isGps()) {
IntentFilter intentFilter = new IntentFilter(Util.LOCAL_RECEIVER);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
workoutReceiver = new WorkoutReceiver();
registerReceiver(workoutReceiver, intentFilter);
if (!onCreate) {
if (!Util.isGPSEnabled(this)) {
displayGPSAlert();
}
if (!preferences.isTryOut()) {
Request.getRequest().sendRequest(Request.GET_ALL_TRACE_USER, this, this, RequestParameterBuilder.buildMapForUserId(this));
}
}
}
timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
if (preferences.isGps()) {
WorkoutServiceHelper.getWorkoutServiceHelper(MainActivity.this).connect();
}
if (!preferences.isWorkoutPaused()) {
history.duration++;
history.calories = HWUtil.calculateCalorie(history, MainActivity.this);
history.cascadeSave();
}
if (history.duration % 5 == 0 && preferences.isTrace() && !preferences.isRequestSent()) {
//Sync record every five second
UserHistoryModel historyModel = history.loadAll();
if (Validator.isNotNull(historyModel)) {
UserHistory uh = convertUserHistoryModelToUserHistory(historyModel);
/*
don't set history pictures when tracing
*/
uh.setHistoryPictures(null);
uh.setId(uh.getUniqueId());
preferences.setRequestSent(true);
Request.getRequest().sendJsonRequest(Request.ADD_USER_HISTORY, MainActivity.this, MainActivity.this, RequestParameterBuilder.buildJsonObjectFromUserHistory(uh));
}
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if (getSupportFragmentManager().findFragmentByTag(TabFragment.class.getName()) != null) {
TabFragment tabFragment = (TabFragment) getSupportFragmentManager().findFragmentByTag(TabFragment.class.getName());
if (tabFragment.getCurrentFragment() instanceof UpdateListener) {
((UpdateListener) tabFragment.getCurrentFragment()).update();
}
} else if (getSupportFragmentManager().findFragmentByTag(FullMapFragment.class.getName()) != null) {
FullMapFragment mapFragment = (FullMapFragment) getSupportFragmentManager().findFragmentByTag(FullMapFragment.class.getName());
mapFragment.update();
}
}
});
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
}
}
whenever user starts any workout/after pause i m calling this method
I have just started exploring google-play-services-turnbased APIs. Till now I have been successful in creating a match. But from the documentation I haven't been able to figure out how to player's score after he completes his turn.
This is my onClickStartMatch method.
public void onStartMatchClicked() {
Intent intent =
Games.TurnBasedMultiplayer.getSelectOpponentsIntent(mHelper.getApiClient(), 1, 7, true);
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
This is my onActivityResult method in my main activity class.
if (request == RC_SELECT_PLAYERS) {
if (response != RESULT_OK) {
// user canceled
return;
}
// Get the invitee list.
final ArrayList<String> invitees =
data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// Get auto-match criteria.
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers = data.getIntExtra(
Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
TurnBasedMatchConfig tbmc = TurnBasedMatchConfig.builder()
.addInvitedPlayers(invitees)
.setAutoMatchCriteria(autoMatchCriteria)
.build();
// Create and start the match.
Games.TurnBasedMultiplayer
.createMatch(mHelper.getApiClient(), tbmc)
.setResultCallback(new MatchInitiatedCallback());
}
This is my MatchInitiatedCallback class
public class MatchInitiatedCallback implements
ResultCallback<TurnBasedMultiplayer.InitiateMatchResult>,OnTurnBasedMatchUpdateReceivedListener {
#Override
public void onResult(TurnBasedMultiplayer.InitiateMatchResult result) {
// Check if the status code is not success.
Status status = result.getStatus();
if (status.isSuccess()) {
Log.d("turnbased","Turn Based Match Initiated successfully with result: "+status.getStatusMessage());
return;
}
TurnBasedMatch match = result.getMatch();
// If this player is not the first player in this match, continue.
if (match.getData() != null) {
showTurnUI(match);
return;
}
// Otherwise, this is the first player. Initialize the game state.
initGame(match);
// Let the player take the first turn
showTurnUI(match);
}
public void showTurnUI(TurnBasedMatch match){
if(match.getStatus() == TurnBasedMatch.MATCH_STATUS_ACTIVE){
if(match.getTurnStatus() == TurnBasedMatch.MATCH_TURN_STATUS_MY_TURN){
turnBasedMatchData = match.getData();
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(), "score:400".getBytes(Charset.forName("UTF-16")),null).setResultCallback(updateMatchResult());
}
}
}
public void initGame(TurnBasedMatch match){
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(),"score:605".getBytes(Charset.forName("UTF-16")),match.getParticipantId(Games.Players.getCurrentPlayerId(mHelper.getApiClient()))).setResultCallback(updateMatchResult());
}
public ResultCallback<TurnBasedMultiplayer.UpdateMatchResult> updateMatchResult(){
return null;
}
#Override
public void onTurnBasedMatchReceived(TurnBasedMatch turnBasedMatch) {
Log.d("turn-based","Player played his turn");
}
#Override
public void onTurnBasedMatchRemoved(String s) {
}
}
}
Also it would helpful if some can properly explain how to continue a game a game from start and when to submit score and how.
Figured it out. This is how you can do it.
public byte[] persist() {
JSONObject retVal = new JSONObject();
try {
retVal.put("turnCounter", 2);
retVal.put("score1",100);
retVal.put("score2",200);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String st = retVal.toString();
Log.d(TAG, "==== PERSISTING\n" + st);
return st.getBytes(Charset.forName("UTF-8"));
}
Games.TurnBasedMultiplayer.takeTurn(mHelper.getApiClient(),match.getMatchId(),persist(),null).setResultCallback(updateMatchResult());