- 4 המשתנים העליונים מתארים את הרכיבים המופיעים ב-game.xml. כאשר pushButton מתאר את הכפתור שהמשתמש יצטרך ללחוץ, scoreTextView יציג את התוצאה של המשתמש, timeTextView יציג את זמן המשחק ו-gameZoneLayout מכיל את האזור שבו הכפתור שלנו יתרוצץ.
- 4 המשתנים האמצעים מאפשרים לנו ליצור את תהליך המשחק. המשתנה ה-2 (gameTimer) הוא ה-Timer המרכזי של המשחק. Timer היא מחלקה המאפשרת לנו לבצע פעולה מסוימת במחזוריות מסוימת. ניתן לקרוא עלייה בעמוד הבא. משתנה ה-gameTimer אחראי להזיז את הכפתור שלנו כל 500 אלפיות השנייה (חצי שנייה). המשתנה האחראי לקצב התזוזה של הכפתור הוא המשתנה ה-4 (updatePeriod) וערכו הוא 500. המשתנה ה-3 (stopperTimer) אחראי לעדכן את שעון המשחק כל פרק זמן מסוים. מפני ש-Timers עובדים בהליך נפרד מן הליך ה-UI עלינו לדאוג שכל הפעולות יבוצעו מן ההליך הראשי (הליך ה-UI). עקב כך, אנו משתמשים במשתנה ה-1 (uiHandler). משתנה זה מאפשר לנו "לזרוק" פקודות להליך הראשי שיבצע. ניתן לקרוא על Handlers בעמוד הבא. בנוסף ניתן לקרוא על שילוב של Timer עם Handler בעמוד הבא.
- 3 המשתנים התחתונים מתארים את משתני המשחק כמו תוצאה, זמן שעבר וכו' . משתנה ה-isPlaying יהיה "אמת" אם כרגע אנו משחקים. משתנה ה-score מכיל את התוצאה של המשתמש. משתנה ה-startTime מכיל את הזמן שבו המשחק התחיל באלפיות השנייה. בהמשך נבין מה השימוש שלו.
- המשתנה האחרון mediaPlayer מאפשר לנו להפעיל סאונד כאשר הכפתור שלנו נלחץ. בהמשך המדריך ניראה איך משתמשים בו.
@Override
public void onClick(View v) {}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);/* Setting variables pointing to their XML views */
scoreTextView = (TextView) findViewById(R.id.scoreTextView);
timeTextView = (TextView) findViewById(R.id.timeTextView);
pushButton = (ImageButton) findViewById(R.id.pushButton);
gameZoneLayout = (RelativeLayout) findViewById(R.id.gameZoneLayout);
uiHandler = new Handler();
gameTimer = new Timer();
stopperTimer = new Timer();
//Allows us to handle push button
pushButton.setOnClickListener(this);
pushButton.setOnKeyListener(this);
//Preparing our push button media player to be ready
mediaPlayer = MediaPlayer.create(this, R.raw.pushbutton_sound);
try { mediaPlayer.prepare(); }
catch (Exception ex) {}
//Allows us to control the media volume using volume controls
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
- נתנו לכל משתני הרכיבים את הרכיבים הנמצאים במסמך ה-game.xml. כעת נוכל להתייחס אליהם. בדיוק כמו שעשינו בתחילת מסמך ה-MainActivity.
- ביצענו אתחול ראשוני למשתני תהליך המשחק (uiHandler, gameTimer ו-stoppperTimer).
- הוספנו Callbacks למשתנה ה-pushButton כך שנוכל לזהות לחיצות עליו.
- השתמשנו במשתנה ה-mediaPlayer בכדי לייבא את סאונד הלחיצה. את קובץ ה-pushbutton_sound.wav עלינו לשים בתיקיית ה-raw אשר נמצאת תחת תיקיית ה-res. ניתן לקרוא על מחלקת ה-MediaPlayer בעמוד הבא. בקצרה: מחלקה זו מאפשרת לנו לנגן קבצי מדיה. מתודה ה-MediaPlayer.create מאפשרת לנו ליצור אובייקט נגן חדש ממשאב הקיים באפליקציה. פונקציית ה-mediaPlayer.prepare() מכינה את הנגן לקראת נגינה.
- הפקודה האחרונה setVolumeControlStream מאפשרת לנו לומר לאנדרואיד שה-Activity שלנו מפעיל סאונד ואנו מעוניינים לשלוט עליו באמצעות כפתורי ה-Volume.
@Override
protected void onDestroy() {
super.onDestroy();//Final clean up
mediaPlayer.release();
mediaPlayer = null;
}
@Override
public void onClick(View v) {
if (isPlaying) {
score += 1;
updateScore();
mediaPlayer.start();
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
//Letting the user use the BACK button normally while avoiding other user input (preventing user from click on the "PUSH" button using keys)
if (keyCode == KeyEvent.KEYCODE_BACK)
return false;return true;
}
void startGame() {
score = 0;
updateScore();
startTime = System.currentTimeMillis();
gameTimer.scheduleAtFixedRate(new GameTimerTask(), 0, updatePeriod);
stopperTimer.scheduleAtFixedRate(new StopperTimerTask(), 0, 50);
isPlaying = true;
}
- מאפסת את תוצאת המשחק ומעדכנת אותה.
- בודקת את הזמן הנוכחי ומכניסה אותו למשתנה startTime.
- מתחילה את שעון ה-gameTimer האחראי להזיז את הכפתור למיקומים שונים על המסך. הפרמטר הראשון הוא מחלקה שאנחנו יצרנו אשר אחראית לפעולה שיש לבצע ונסקור אותה בהמשך. הפרמטר השני אומר בעצם לשעון שאנו רוצים להתחיל את לבצע את הפעולה מעכשיו. הפרמטר השלישי מתאר את הקצב שבו הפעולה תחזור. כפי שראינו בהכרזת המשתנה פונקציה זו בעלת ערך של 500 אלפיות השנייה. או במילים אחרות חצי שניה. ניתן לקרוא על פונקצית ה-Timer.scheduleAtFixedRate שבה השתמשנו בעמוד הבא.
- מתחילה את שעון העצר (סטופר). הפרמטר הראשון מתאר את מחלקה המבצעת את פעולת בדיקת ועדכון הזמן. הפרמטר השני אומר שיש להתחיל את הפעולה מיד. הפרמטר השלישי אומר שיש לבצע עדכון לשעון העצר כל 50 אלפיות השנייה.
- משנה את ערך משתנה ה-isPlaying ל"אמת". כך כל פעם שנלחץ על כפתור ה-pushButton המשתמש יקבל נקודות מפני שהמשחק התחיל.
class GameTimerTask extends TimerTask {@Override
public void run() {
uiHandler.post(new Runnable() {
@Override
public void run() {
placePushButtonRandomly();
}
});
}
}
void placePushButtonRandomly() {
Random rnd = new Random();int left = rnd.nextInt(gameZoneLayout.getWidth() – pushButton.getWidth());
int top = rnd.nextInt(gameZoneLayout.getHeight() – pushButton.getHeight());
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) pushButton.getLayoutParams();
layoutParams.setMargins(left, top, 0, 0);
pushButton.setLayoutParams(layoutParams);
}
- מחשבת את הערכים האקראיים של המיקום השמאלי והעליון של הכפתור. היא עושה זאת על ידי שימוש במחלקת ה-Random. מחלקה זו נותנת לנו מספר אקראי מ-0 ועד מספר מסוים. המיקום המקסימלי שנרצה למשל שהכפתור שלנו ינוע בציר ה-X יהיה עד הדופן הימני. לכן יהיה עלינו להסיר את רוחב הכפתור עם רוחב איזור המשחק. ניתן להסתכל באיור הבא ולהבין למה:
- לאחר החישוב המשתנים left ו-top מכילים את המיקום על ציר ה-X וה-Y שהכפתור שלנו יוצב. כעת כל מה שעלינו לעשות זה לשנות את תכונות ה-Margin הקיימות עם המשתנים האלו. לכן נשיג את הפרמטרים הנוכחיים של כפתור ה-pushButton על ידי שימוש בפונקציית ה-getLayoutParams, נשנה את תכונות ה-Margins על ידי שימוש בפונקציית ה-setMargins וניתן לרכיב ה-pushButton את הפרמטרים עם השינויים. מחלקת ה-LayoutParams מכילה בתוכה מידע על איך הרכיב שלנו יראה תחת ה-Layout שבו הוא נמצא. ניתן לקרוא על מחלקה זו בעמוד הבא.
class StopperTimerTask extends TimerTask {@Override
public void run() {
uiHandler.post(new Runnable() {
@Override
public void run() {
long timePassed = System.currentTimeMillis() – startTime; //Calculating time passed from the game start
timeTextView.setText(getTimeString(System.currentTimeMillis() – startTime)); //Updating the stopper
//If the game time passed 30 seconds
if ((timePassed / 1000) >= 30)
stopGame(true);
}
});
}
}
- בודק את הזמן שעבר מתחילת הזמן באמצעות חיסור הזמן הנוכחי עם הזמן ההתחלתי. זוכרים את משתנה ה-startTime? בדיוק לכך השתמשנו בו! הזמן המוחזר לנו הוא באלפיות השניה.
- מעדכנים את התצוגה עם הזמן הנוכחי. משתנה ה-timeTextView הוא בעצם הרכיב שאחראי לתצוגת שעון העצר. כפי שניתן ליראות אנו משתמשים במתודת ה-getTimeString. זו מתודה שאנו יצרנו ומיד ניראה מה היא מכילה בתוכה. כל מה שעלינו לדעת זה שהיא ממירה זמן באלפיות השנייה למחרוזת שתציג את הזמן בשניות.
- בודקים אם הזמן עבר את מגבלת ה-30 שניות. אם כן אנו עוצרים את המשחק באמצעות מתודת ה-stopGame. זו היא מתודה שאנו כתבנו ומיד ניראה כיצד היא עובדת. הפרמטר היחיד שהמתודה מקבלת זה האם להציג את הדיאלוג עם תוצאות המשתמש או להפסיק את המשחק מבלי להציג כלום. אנו רוצים שלאחר שעבר זמן המשחק המשתמש יראה את התוצאה שלו ולכן הפרמטר מכיל פסוק אמת.
String getTimeString(long milliTime) {
int seconds = (int) milliTime / 1000;
int milli = (int) (milliTime % 1000) / 10;return getClockString(seconds) + ":" + getClockString(milli);
}
String getClockString(int digit) {
if (digit < 10)
return "0" + digit;
return String.valueOf(digit);
}
- ממירה את הזמן שסיפקנו לה באלפיות השניות וממירה אותו לשניות. היא עושה זאת על ידי חילוק אלפיות השנייה ב-1000 וכך היא משיגה את מספר השניות שעברו.
- משיגה את מאיות השנייה של אותה השנייה על ידי השגת שארית החלקית ב-1000 וחילוק שלה ב-10. על ההסבר המתמטיקאי לא נעבור.
- לבסוף הפונקציה מחזירה מחרוזת בפורמט של שניות : מאיות. היא עושה זו על ידי שימוש בפונקציית ה-getClockString אשר עושה את הדבר הפשוט הבא: אם המספר שהיא מקבלת קטן מ-10 היא מוסיפה לו 0 בצדו השמאלי ומחזירה אותו בתור מחרוזת. אם המספר גדול מ-10 היא מחזירה אותו כמו שהוא רק בתור מחרוזת.
void stopGame(boolean showGameOver) {
isPlaying = false;gameTimer.cancel();
gameTimer = new Timer();
stopperTimer.cancel();
stopperTimer = new Timer();
if (showGameOver)
showDialog(Dialogs.DIALOG_GAMEOVER);
}
- משנה את משתנה ה-isPlaying לשקר. המשחק נגמר ועלינו לחסום את המשתמש מלקבל נקודות נוספות.
- מפסיקה את שעון ה-gameTimer ושעון ה-stopperTimer. היא מאתחלת אותן מחדש בכדי שלא תתרחש שגיאה כאשר נרצה להשתמש בהם שוב.
- בודקת את הפרמטר שסיפקנו לה – אם הוא פסוק אמת נציג את דיאלוג ה-Game Over.
class Dialogs {
public final static int DIALOG_GAMEOVER = 0;
}@Override
protected Dialog onCreateDialog(int id) {
Dialog diag = null;
switch (id) {
case Dialogs.DIALOG_GAMEOVER:
return new AlertDialog.Builder(this)
.setTitle("Game Over!")
.setMessage("Your score is: " + score + "!")
.setPositiveButton("Accept", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { dialog.cancel(); }
})
.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) { finish(); }
})
.create();
}
return diag;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);if (hasFocus)
startGame();
else
stopGame(false);
}
- עלה לגמרי והמשתמש כרגע נמצא בפוקוס עליו.
- החלון אינו ניראה למשתמש ואיבד פוקוס. יש לכך סיבות רבות כמו: המשתמש נעל את המכשיר, חזר לתפריט הראשי או לחץ על כפתור הבית שהביא אותו למסך הבית של המכשיר. ניתן להבחין באיזה מצב אנו נמצאים על ידי הפרמטר ה-hasFocus. פרמטר זה יהיה פסוק אמת אם המשתמש כרגע נמצא במצב הראשון ויכיל פסוק שקר אם המשתמש נמצא במצב השני.
כאשר המשתמש נמצא במצב הראשון נתחיל את המשחק. אם המשתמש נמצא במצב השני נעצור את המשחק. שימו לב כי אנו לא מציגים דיאלוג Game Over זאת מפני שזמן המשחק לא עבר.
מדריך איכותי בטירוף
תודה רבה!!
כל הכבוד
סוף סוף מדריך מ- א ועד ת.
מדריך מעולה !
ממש מדריך טוב ! תודה !
תודה@
נהדר תודה לך
איזה מקצוענות…כל הכבוד !
מדריך מעולה!
קצר וקולע, כל הכבוד!
הורדה של הכתבה ?
אפשר להוריד את הכתבה בפורמט pdf ?
כל הכבוד.
דרך אגב מישהו פעם ניסה לפתח עם flex?
זה מומלץ?
שי, יש אפשרות ליצור איתך קשר במייל?
אם כן, אשמח אם תשלח לי מייל לכתובת הבאה: [email protected]
אני זקוק לעזרה קטנה, שאני מאמין שלא תיהיה לך בעיה מיוחדת לעזור בה, תודה.
פששש
אחלה, כל הכבוד על ההשקעה.
hwzone – תמשיכו להביא כאלו כתבות !
מדריך מצויין אך
רק דבר אחד חסר לי וזה הסבר על google adsense ואיך משתמשים ומשלבים באפליקציה.
תותחים!!
כל הכבוד לhwzone תמשיכו להפציץ במדריכים מעולים!!
שאלה
לא הבנתי מאיפה מחלצים את resources.rar
קישור
איפה הקישור למדריך ?
מדריך מושקע לפיתוח אפליקציות
כל הכבוד על המדריך
רעיון לאפליקציה
שלום יש לי רעיון.
אפליקציה בשם המשמרת שלי . האפליקציה חיונית כיום בכל מפעל שמכבד את עצמו.כולנו בעלי סמארטפונים , אנחנו רוצים כל יום לדעת את המשמרת שלנו בעבודה . האפליקציה שאני בונה תסונכרן מול מחשבי החברה ותתריע על כל משמרת שאתה עושה. באיזה שעה מתחילה ובאיזה מסתיימת . שעת איסוף ועוד .. איזה משכורת אתה מקבל , כמה שעות אתה עובד. כמה % יש תוספת , מי שמעוניין לבנות איתי את האפילקציה ולהתחלק ברווחים שייצור קשר.
מדריך מצויין !!יש אפשרות ליצור איתך קשר?
שי אשמח אם תיצור איתי קשר במייל יש לי כמה שאלות ואשמח אם תוכל לעזור לי
[email protected]
בעניין תוכנת הeclipse
מלבד החלון הראשי שנוצר עם הפרויקט שלנו (MainActivity) אשר יכיל את התפריט הראשי של המשחק, ניצור חלון נוסף אשר יכיל את המשחק עצמו.
נעשה זאת על ידי העתקת קובץ ה-MainActivity ושינוי שמו ל-GameActivity. כעת נעשה את אותו הדבר לקובץ ה-main.xml שבתיקיית ה-reslayout ונקרא לו game.xml.
אני חייב עזרה בזה לא הבנתי איזה קובץ בדיוק להעתיק מאיפה ולאיפה אשמח למי שיעזור לי . המייל שלי [email protected] תודה
כל הכבוד!!!! מאמר מעולה.
מדריך טוב,
אבל הקבצים להורדה לא עובדים.
אם אפשר לסדר/יש למישהו ויכול להעלות שוב…
תודה!