English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
أعتقد أن الجميع لعبوا لعبة الأحجية في صغارهم، اليوم، مع تزايد انتشار الهواتف الذكية، يصبح هناك المزيد من الألعاب التي يمكن اللعب بها على الهاتف الذكي، لذا، نحن نعيد التفكير في أيامنا الصغيرة، ونكتب لعبة الأحجية البسيطة هذه، كما يمكن أيضًا تعميق المعرفة الأساسية لـ Android.
بالتقاليد، أولاً صورة العرض:
هنا قمت بتصرف القليل جدًا من الصور لتحقيق تأثير العرض، يمكن تعديل ذلك في الكود.
أولاً، هناك صورة افتراضية يمكن استخدامها للعب اللعبة، يمكنك أيضًا اختيار صورة تفضيلية للعب اللعبة، وسيتم تسجيل عدد الخطوات المتخذة في عملية اللعب، وسيتم عرض تلميح ابتسامة عند الفوز في اللعبة، والفوز، وأي عدد خطوات تم استخدامه.
النقطة: يمكن للذين يهتمون بالاستمرار في التوسع في هذا المجال، مثل إضافة خيارات تعديل صعوبة اللعبة، يمكن تقسيم الصور إلى مربعات أصغر وأكثر.
الفكرة الأساسية: قطع الصورة الكبيرة إلى مكعبات صغيرة، تسجيل معلومات كل مكعب صغير في مصفوفة، عرض كل مكعب صغير باستخدام GridLayout، وتعيين مكعب صغير كفراغ (يمكن تبادل الفضاء مع المكعبات المجاورة)، وإضافة أحداث النقر وال手势 على مكعبات GridLayout في الشاشة بأكملها، في كل مرة تنقر أو يتم手势، يتم التحقق مما إذا كان يمكن تحريك المكعب، وأخيرًا، يظهر رسالة النصر عند الانتصار في اللعبة.
لا أقول كثيرًا، لذا، يلي خطوات تنفيذ لعبة الألغاز خطوة بخطوة.
1. فئة مكعب صغير.
هذا هو item لكل متغير مكعب صغير من كل مكعب صغير، فئة، تستخدم لإدارة قطع الصورة الكبيرة إلى كل مكعب صغير من كل مكعب الصغير. بسيط للغاية، فقط متغيرات وطرق Setter وGetter مباشرة، أرفع الكود~
/** * تم إنشاؤه بواسطة yyh في 2016/10/21. */ public class GameItemView{ /** * معلومات كل مكعب صغير */ //每个小方块的实际位置x, private int x=0; //每个小方块的实际位置y, private int y=0; //每个小方块的图片, private Bitmap bm; //每个小方块的图片位置x, private int p_x=0; //每个小方块的图片位置y. private int p_y=0; public GameItemView(int x, int y, Bitmap bm) { super(); this.x = x; this.y = y; this.bm = bm; this.p_x=x; this.p_y=y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public Bitmap getBm() { return bm; } public void setBm(Bitmap bm) { this.bm = bm; } public int getP_x() { return p_x; } public void setP_x(int p_x) { this.p_x = p_x; } public int getP_y() { return p_y; } public void setP_y(int p_y) { this.p_y = p_y; } /** * تحديد موقع كل مربع صغير إذا كان صحيحًا * @return */ public boolean isTrue(){ if (x==p_x&&y==p_y){ return true; } return false; } }
2.تنسيق الواجهة الرئيسية
الواجهة الرئيسية بسيطة، زر Button، لتبديل الصور، ImageView، لعرض الصورة الأصلية، GridLayout لتنفيذ لعبة التلبيس، وأخيرًا، TextView، لعرض عدد الخطوات التي استغرقتها لإنهاء اللعبة. النسخة التالية للتنسيق:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/ll" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/bt_choice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择图片" android:adjustViewBounds="true" /> </LinearLayout> <ImageView android:id="@+id/iv" android:layout_below="@id/ll" android:adjustViewBounds="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/haizei" android:layout_marginTop="3dp" </ImageView> <!-- 游戏的主界面--> <GridLayout android:layout_marginTop="3dp" android:layout_below="@id/iv" android:id="@+id/gl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnCount="5" android:rowCount="3" android:adjustViewBounds="true" > </GridLayout> <TextView android:id="@+id/tv_step" android:layout_below="@id/gl" android:layout_marginTop="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="已用步数:0" android:textSize="26sp" /> </RelativeLayout>
3.打开图片选择图片
Button设置点击事件,调用startActivityForResult(Intent intent,int requestCode);方法,来获取图片。
bt_choice.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {}} Intent intent= new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent, CHOICE_PHOTO);//فتح مجلد الصور } });
أعيد كتابة طريقة onActivityResult(int requestCode, int resultCode, Intent data) في Activity لعرض الصورة المختارة، وإعداد اللعبة. (بعد اختيار الصورة، يجب تقسيم الصورة وتحديد اللعب المتعدد.)
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case CHOICE_PHOTO: if (resultCode==RESULT_OK){ // التحقق من إصدار نظام الهاتف if (Build.VERSION.SDK_INT>=19){ handleImageOnKitKat(data); // الحصول على الصورة في imageView BitmapDrawable bitmapDrawable= (BitmapDrawable) photo.getDrawable(); bt_tupan=bitmapDrawable.getBitmap(); // إزالة المربعات الصغيرة من GridLayout الحالي، removeGameItem(); // قطع الصورة الجديدة إلى مربعات صغيرة وإضافتها إلى GridLayout. setGameItem(); // البدء في اللعبة startGame(); }else { handleImageBeforeKitKat(data); // الحصول على الصورة في imageView BitmapDrawable bitmapDrawable= (BitmapDrawable) photo.getDrawable(); bt_tupan=bitmapDrawable.getBitmap(); // إزالة المربعات الصغيرة من GridLayout الحالي، removeGameItem(); // قطع الصورة الجديدة إلى مربعات صغيرة وإضافتها إلى GridLayout. setGameItem(); // البدء في اللعبة startGame(); } } } }
ثم يأتي اختيار طريقة تنفيذ اختيار الصورة. التعليقات واضحة، لا أقول أكثر.تركز اهتمامنا على تنفيذ اللعب المتعدد وال手势ات، حيث يوجد العديد من طرق اختيار الصورة. لا أتحدث عن ذلك، هناك إطارات جاهزة على الإنترنت.
// الهاتف الذي حجمه لا يتجاوز 19 للحصول على البيانات private void handleImageBeforeKitKat(Intent data) { Uri uri =data.getData(); String imagePath = getImagePath(uri, null); displayImage(imagePath); } /** * طريقة أخذ البيانات لجهاز ذو هاتف أكبر من 19 * @param data */ @TargetApi(Build.VERSION_CODES.KITKAT) private void handleImageOnKitKat(Intent data) { String imagePath=null; Uri uri=data.getData(); if (DocumentsContract.isDocumentUri(this,uri)){ //إذا كان url نوع document،معالجة via id document. String docId=DocumentsContract.getDocumentId(uri); if ("com.android.providers.media.documents".equals(uri.getAuthority())){ String id =docId.split(":")[1];//استخراج id في شكل رقمي; String selection= MediaStore.Images.Media._ID+"="+id; imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection); else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())){ Uri contenturi= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId)); imagePath=getImagePath(contenturi,null); } else if ("content".equalsIgnoreCase(uri.getScheme())){ //ليس uri نوع document،استخدم الطريقة العادية للمعالجة. imagePath=getImagePath(uri,null); } displayImage(imagePath); } /** * عرض الصورة * @param imagePath // مسار الصورة. */ private void displayImage(String imagePath) { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); if (isHeigthBigWidth(bitmap)) { Bitmap bt = rotaingImageView(bitmap);// دوران الصورة 90 درجة. Bitmap disbitmapt = ajustBitmap(bt); photo.setImageBitmap(disbitmapt); } else { Bitmap disbitmap = ajustBitmap(bitmap); photo.setImageBitmap(disbitmap); } } } /** * تعديل اتجاه الصورة * @param bitmap * @return */ private Bitmap rotaingImageView(Bitmap bitmap) { // عملة دوران الصورة Matrix matrix = new Matrix();; matrix.postRotate(270); // إنشاء صورة جديدة Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } /** * حصول على مسار الصورة * @param externalContentUri * @param selection * @return */ private String getImagePath(Uri externalContentUri, String selection) { String path=null; Cursor cursor=getContentResolver().query(externalContentUri, null, selection, null, null); if (cursor!=null){}} if (cursor.moveToFirst()){ path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } } cursor.close(); return path; }
4. عملية تكوين مربعات اللغز المختلفة.
نظرًا لأن GridLayout هو أكثر طريقة سهولة لتحقيق ذلك، نستخدم GridLayout لعرض مربعات الصورة المقطعة بعد القطع، ونستخدم مصفوفة ImageView لتحفظ معلومات كل مربع صغير، ونفترض أن يكون المربعات الصغيرة الأخيرة مربعات فراغ.
أولاً، هناك جميع المتغيرات المطلوبة. التعليقات واضحة.
/** *استخدام مصفوفة ثنائية لإنشاء عدة مربعات صغيرة للعبة */ private ImageView[][] iv_game_arr=new ImageView[3][5]; /** *واجهة اللعبة الرئيسية * */ private GridLayout gl_game_layout; // الصف والعمود للمربعات الصغيرة private int i; private int j; /**مربعات الفراغ العالمية*/ private ImageView iv_null_imagview;
ثم، من Imageview نحصل على الصورة، ونقوم بتقطيع الصورة بناءً على عدد معين من الصفوف والعمود (هنا يتم إعداد اللغز مع 3 صف و5 عمود). يتم حفظ معلومات كل مربع صغير في مصفوفة Imageview. يتم تعيين Tag لكل مربع صغير ومستمع للنقر.
private void setGameItem() { //调整图片的尺寸 Bitmap abitmap=ajustBitmap(bt_tupan); int ivWidth=getWindowManager().getDefaultDisplay().getWidth()/5; // كل مربع صغير لكل لعبة عرض وارتفاع. يتم قطعها إلى مربعات مستطيلة int tuWidth=abitmap.getWidth()/5; لـ(int i=0;ي<i<iv_game_arr.length;ي++){ لـ(int j=0;ج<iv_game_arr[0].length;ج++){ //将大图切成小方块 Bitmap bm = Bitmap.createBitmap(abitmap, j * tuWidth, i * tuWidth, tuWidth, tuWidth); iv_game_arr[i][j] = new ImageView(this); iv_game_arr[i][j].setImageBitmap(bm); //تعيين رسم كل صغير iv_game_arr[i][j].setLayoutParams(new RelativeLayout.LayoutParams(ivWidth, ivWidth)); //إعداد المسافة بين القطع iv_game_arr[i][j].setPadding(2, 2, 2, 2); iv_game_arr[i][j].setTag(new GameItemView(i, j, bm)); //ربط البيانات المخصصة iv_game_arr[i][j].setOnClickListener(new View.OnClickListener() { ....... );
بالطبع، لا يمكن أن تكون جميع الصور التي نختارها تتوافق مع الأحجام القياسية، لذا يجب علينا تعديل الصور قبل قطعها. قم بتعديل الصورة لتحقيق نسبة 5:3. (بهذا يمكن قطع الصورة إلى 3 أسطر و 5 أعمدة من الصغائر بشكل صحيح) هنا، أضفت مساحة بين كل صغير إلى عرض كل صغير.
//تغيير حجم الصورة private Bitmap ajustBitmap(Bitmap bitmap) { int width = getWindowManager().getDefaultDisplay().getWidth() - (iv_game_arr[0].length - 1) * 2; int heigth = width / 5 * 3; Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, width, heigth, true); return scaledBitmap; }
وضع كل صغير في GridLayout.
/** * وضع الصغيرات داخل GridLayout */ private void startGame() { tv_step.setText("عدد الخطوات المستخدمة: 0"); for (i = 0; i <iv_game_arr.length; i++){ for (j = 0; j <iv_game_arr[0].length; j++){ gl_game_layout.addView(iv_game_arr[i][j]); } } //الجسر الأخير يتم تعيينه كحالة خالية. setNullImageView(iv_game_arr[i-1][j-1]);
5. The click event and gesture judgment process of the small block.
This is the core of the puzzle game, understanding the movement and change rules of the small blocks will also understand the puzzle game.
For the click event, first obtain the various information (position, pattern) of the clicked small block and the position information of the blank small block, determine whether the clicked small block is adjacent to the blank small block, if adjacent, then move and exchange data (using TranslateAnimation to implement the moving animation), if not adjacent, then no operation.
a. The method for determining whether the clicked block and the blank block are adjacent
/** * Determine whether the current clicked block is adjacent to the empty block. * @param imageView The current clicked block * @return true:adjacent. false:Not adjacent. */ public boolean isAdjacentNullImageView(ImageView imageView){ //获取当前空方块的位置与点击方块的位置 GameItemView null_gameItemView= (GameItemView) iv_null_imagview.getTag(); GameItemView now_gameItem_view = (GameItemView) imageView.getTag(); if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()+1==null_gameItemView.getX()){//当前点击的方块在空方块的上面 return true; }else if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()+1){//当前点击的方块在空方块的下面 return true; }else if(null_gameItemView.getY()==now_gameItem_view.getY()+1&&now_gameItem_view.getX()==null_gameItemView.getX()){//当前点击的方块在空方块的左面 return true; }else if(null_gameItemView.getY()+1==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()){ ////当前点击的方块在空方块的右面 return true; } return false; }
b.بعد ذلك يتم التحقق من التشابه وإذا كان قريبًا يدخل في طريقة تبادل بيانات البرمجية
هناك طريقة تعريف مكررة،هل تحتاج إلى تأثير الحركة،تبادل البيانات بدون تأثير الحركة هو تحضير لتشويه اللعبة عند بدء اللعبة. سيتم عرض رمز تبادل النواة هنا. بعد كل تبادل يجب التحقق من الانتصار (هل تم إكمال اللعبة~).
//الحصول على بيانات البرمجية المضغوطة GameItemView gameItemView = (GameItemView) itemimageView.getTag(); //ضبط صورة البرمجية الفارغة على صورة البرمجية المضغوطة iv_null_imagview.setImageBitmap(gameItemView.getBm()); //الحصول على بيانات البرمجية الفارغة GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag(); //تبادل البيانات (إدخال بيانات البرمجية المضغوطة في البرمجية الفارغة) null_gameItemView.setBm(gameItemView.getBm()); null_gameItemView.setP_x(gameItemView.getP_x()); null_gameItemView.setP_y(gameItemView.getP_y()); //ضبط البرمجية الحالية على مربع فارغ setNullImageView(itemimageView); if (isStart){ isGameWin();//عند الانتصار،سيتم عرض رسالة إشعار }
c.ضبط الحركة عند التبادل
عندما يتم ضبط الحركة،يتم أولاً تحديد الاتجاه،حسب الاتجاه يتم ضبط الحركة المختلفة،ثم يتم الاستماع إلى اكتمال الحركة،ويتم إجراء عملية تبادل البيانات. أي أن b.بعد ذلك يتم التحقق من التشابه وإذا كان قريبًا يدخل في طريقة تبادل بيانات البرمجية. وأخيرًا يتم تنفيذ الحركة.
//1.إنشاء حركة،ضبط الاتجاه،تحديد المسافة المتحركة //تحديد الاتجاه،ضبط الحركة if (itemimageView.getX()>iv_null_imagview.getX()){//البرمجية الحالية في أعلى مربع الفارغ //تحريك للأسفل translateAnimation = new TranslateAnimation(0.1f,-itemimageView.getWidth(),0.1f,0.1f); }else if (itemimageView.getX()<iv_null_imagview.getX()){//الكتلة المضغوطة الحالية في الأسفل من الكتلة الفارغة // تحريك إلى أعلى boolean f=itemimageView.getX()<iv_null_imagview.getX(); //Log.i("نقر الكتلة","sssssssssssssssssssssssss"+f); translateAnimation = new TranslateAnimation(0.1f,itemimageView.getWidth(),0.1f,0.1f); }else if (itemimageView.getY()>iv_null_imagview.getY()){//الكتلة المضغوطة الحالية في اليسار من الكتلة الفارغة // تحريك إلى اليمين translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,-itemimageView.getWidth()); }else if(itemimageView.getY()<iv_null_imagview.getY()){//الكتلة المضغوطة الحالية في اليمين من الكتلة الفارغة // تحريك إلى اليسار translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,itemimageView.getWidth()); } // إعداد مختلف معلمات التحريك translateAnimation.setDuration(80); translateAnimation.setFillAfter(true); // إعداد استماع التحريك translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { isAminMove=true; } @Override public void onAnimationEnd(Animation animation) { // انتهاء التحريك، تبادل البيانات ...... } // تنفيذ التحريك itemimageView.startAnimation(ترجمة_التحريك);
The process of click event is completed, next is the event of gesture judgment. That is, not only can move by clicking the small square, but also by gesture to move the small square.
One. create gesture object
complete gesture-related operations in the onFling method.
// create gesture object gestureDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // operation related to gesture ...... }
Next, we perform specific operations in the onFling method
Two. judge the direction of gesture movement
Different moving directions are obtained according to the different return values.
/** * increase gesture sliding, judge sliding up, down, left, right according to gesture * @param start_x gesture start point x * @param start_y gesture start point y * @param end_x gesture end point x * @param end_y gesture end point y * @return 1: up 2: down 3: left 4: right */ public int getDirctionByGesure(float start_x, float start_y, float end_x, float end_y) { boolean isLeftOrRight = (Math.abs(end_x - start_x) > Math.abs(end_y - start_y)) ? true : false; // whether it is left or right if(isLeftOrRight){//أيمن وأيسر boolean isLeft=(end_x-start_x)>0?false:true; if(isLeft){ return 3; }else { return 4; } }else{//أعلى وأسفل boolean isUp=(end_y-start_y)>0?false:true; if (isUp){ return 1; }else { return 2; } } }
Three.تحديد ما إذا كان يمكن التحرك وإجراء عملية التحريك بناءً على اتجاه البلاك الفارغ.
بما أن الحركة هي بيد، فإن الحركة ستكون بالضرورة بلاك حول البلاك الفارغ، لذا يجب التركيز على تحديد اتجاه البلاك الفارغ بالنسبة للبلاك الذي سيتم تحريكه، ومن ثم تحديد ما إذا كان يمكن التحرك بناءً على الاتجاه، ثم إجراء عملية التحريك. (والطريقة changeDateByImageView() هي عملية تبادل بيانات تحريك البلاك وتحريكها. وهي الطريقة التي تُستخدم فيها الأحداث النقر.)
/**إعادة تعريف changeByDirGes(int type) 方法; * تحريك البلاك المتجاور بناءً على اتجاه اليد. * @param type قيمة الاتجاه 1:أعلى 2:أسفل 3:يسار 5:ي右侧 * @param isAnim هل هناك حركة رسومية true:نعم، false:لا */ public void changeByDirGes(int type,boolean isAnim){ //1.الحصول على موضع البلاك الفارغ الحالي. GameItemView null_gameItemView= (GameItemView) iv_null_imagview.getTag(); int new_x=null_gameItemView.getX(); int new_y=null_gameItemView.getY(); //2.إعداد المواضع المتجاورة بناءً على الاتجاه. if (type==1){//يوضح أن البلاك الفارغ في الأعلى من البلاك الذي سيتم تحريكه. new_x++; }else if (type==2){//البلاك الفارغ في الأسفل من البلاك الذي سيتم تحريكه new_x--; }else if (type==3){//البلاك الفارغ في الجانب الأيسر من البلاك الذي سيتم تحريكه new_y++; }else if (type==4){//البلاك الفارغ في الجانب الأيمن من البلاك الذي سيتم تحريكه new_y--; } //3.تحديد ما إذا كانت هذه النقطة الجديدة موجودة if(new_x>=0&&new_x<iv_game_arr.length&&new_y>=0&&new_y<iv_game_arr[0].length){ // هناك،يمكن تبادل البيانات if(isAnim){// هناك تأثير changeDateByImageView(iv_game_arr[new_x][new_y]); }else{ changeDateByImageView(iv_game_arr[new_x][new_y],isAnim); } }else{ // لا تفعل أي شيء } }
حسنًا،حدث اللمس قد تم الانتهاء منه بنجاح~
بالطبع،هناك مكانين يجب الانتباه لهما.1. يجب أولاً تعيين طريقة onTouch() الحالية في Activity،ومن ثم تحويل أحداث اللمس إلى معالجة اللمس،ثم يجب أيضًا تعيين طريقة dispatchTouchEvent()،وفيها يجب أيضًا توزيع أحداث اللمس إلى معالجة اللمس.إذا لم يتم توزيع أحداث اللمس إلى معالجة اللمس،ففي GridLayout،يمكن فقط تحفيز أحداث النقر،وعدم تحفيز أحداث اللمس،وذلك يؤدي إلى عدم عمل أحداث اللمس.2. يجب إضافة علم (flag) لتحديد ما إذا كان هناك تحرك في الوقت الحالي.إذا كان هناك تحرك،فلا يتم القيام بأي شيء،وإلا فإن كل نقر على مكعب صغير،حتى في حالة التحرك،سيؤدي إلى تحفيز أحداث النقر مرة أخرى،وذلك يؤدي إلى تحريك الرسوم البيانية مرة أخرى،وذلك يؤدي إلى تجربة مستخدم سيئة.
@Override public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { gestureDetector.onTouchEvent(ev); return super.dispatchTouchEvent(ev); }
6.طريقة تبديل مكعبات اللعبة عند بدء اللعبة وعرض Toast عند انتهاء اللعبة.
كود بسيط،نقوم بعرض الكود مباشرة،وفيه،يكون Toast المتنقل يحتوي على تأثير عرض مخصص.
// عشوائيةاً،قوموا بقلب ترتيب الصور public void randomOrder(){ // عدد المرات المقلوبة،لراحة الاختبار،تم تعيينها صغيرة. for (int i=0;i<5;i++){ // حسب手势،تبادل البيانات،بدون تأثير حركي. int type = (int) (Math.random()*4)+1; // Log.i("sssssssssfdfdfd","交换次数"+i+"type的值"+type); changeByDirGes(type, false); } } /** * طريقة تحديد انتهاء اللعبة */ public void isGameWin(){ // علامة الانتصار في اللعبة boolean isGameWin =true; // قم بتحليل كل صندوق صغير for (i = 0; i <iv_game_arr.length; i++){ for (j = 0; j <iv_game_arr[0].length; j++){ // لا تقم بالتحقق من الصندوق الفارغ، قم بالتخطي if (iv_game_arr[i][j]==iv_null_imagview){ continue; } GameItemView gameItemView= (GameItemView) iv_game_arr[i][j].getTag(); if (!gameItemView.isTrue()){ isGameWin=false; // قم بالخروج من الدائرة الداخلية break; } } if (!isGameWin){ // قم بالخروج من الدائرة الخارجية break; } } // بناءً على متغير مفتاح لتحديد ما إذا كانت اللعبة انتهت، عند انتهاء اللعبة يظهر تنبيه. if (isGameWin){ // Toast.makeText(this,"لقد ربحت اللعبة",Toast.LENGTH_SHORT).show(); ToastUtil.makeText(this,"تهانيًا، لقد ربحت اللعبة باستخدام"+step+"خطوة",ToastUtil.LENGTH_SHORT,ToastUtil.SUCCESS); step=0; } }
حسنًا، الجزء المهم قد تم بالفعل، هناك أيضًا View مخصص للإشعارات، حول تفاصيل الإشعارات، ستكون في المقالة القادمة، هنا سنوضح بسرعة عملية تنفيذ الإشعار المخصص.
أولاً، قم بإنشاء فئة SuccessToast، (ابتسامة تتضمن العين اليسرى، العين اليمنى، حركة الابتسامة). سنقدم عملية النواة. باستخدام الرسوم المتحركة، سنحقق في عملية رسم الابتسامة بشكل ديناميكي.
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setStyle(Paint.Style.STROKE); // حركة الابتسامة canvas.drawArc(rectF, 180, endAngle, false, mPaint); mPaint.setStyle(Paint.Style.FILL); if (isSmileLeft) { // إذا كانت العين اليسرى، يرسم العين اليسرى canvas.drawCircle(mPadding + mEyeWidth + mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint); } if (isSmileRight) { // إذا كان هناك عين، يرسم العين اليمنى. canvas.drawCircle(mWidth - mPadding - mEyeWidth - mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint); } } /** * طريقة بدء التحريك. * @param startF القيمة البداية * @param endF القيمة النهائية * @param time وقت التحريك * @return */ private ValueAnimator startViewAnim(float startF, final float endF, long time) { // إعداد قيمة البداية والنهاية ل valueAnimator. valueAnimator = ValueAnimator.ofFloat(startF, endF); // إعداد وقت التحريك valueAnimator.setDuration(time); // إعداد الم interpolator. التحكم في سرعة تحريك. valueAnimator.setInterpolator(new LinearInterpolator()); // إعداد المستمع. المستمع إلى تغييرات قيمة التحريك، ويقوم بالرد بشكل مناسب. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mAnimatedValue = (float) valueAnimator.getAnimatedValue(); // إذا كان قيمة value أقل من 0.5 if (mAnimatedValue < 0.5) { isSmileLeft = false; isSmileRight = false; endAngle = -360 * (mAnimatedValue); //إذا كان قيمة value بين 0.55 و 0.7 } endAngle = -180; isSmileLeft = true; isSmileRight = false; //آخر } else { endAngle = -180; isSmileLeft = true; isSmileRight = true; } //إعادة الرسم postInvalidate(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } return valueAnimator; }
ثم قم بإنشاء ملف success_toast_layout.xml، وإكمال تخطيط toast. التخطيط هو إلى اليسار واليمنى (عرض وجه السعادة في اليسار، وTextView الإشارة في اليمين).
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#00000000" android:orientation="vertical" <LinearLayout android:id="@+id/base_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="25dp" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:layout_marginTop="25dp" android:background="@drawable/background_toast" android:orientation="horizontal" <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" <com.example.yyh.puzzlepicture.activity.Util.SuccessToast> android:id="@+id/successView" android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="center_vertical|left" android:layout_margin="10px" android:gravity="center_vertical|left" /> </LinearLayout> <TextView android:id="@+id/toastMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="10dp" android:text="New Text" /> </LinearLayout> </LinearLayout>
في النهاية، قم بإنشاء فئة ToastUtil جديدة لادارة Toast المخصصة.
/** * تم إنشاؤه بواسطة yyh في 2016/10/25. */ النوعية العامة class ToastUtil { النوعية العامة ثابتة LENGTH_SHORT = 0; النوعية العامة ثابتة LENGTH_LONG = 1; النوعية العامة ثابتة SUCCESS = 1; النوعية العامة ثابتة SuccessToast successToastView; النوعية العامة void makeText(Context context, String msg, int length, int type) { Toast toast = new Toast(context); التحويل (النوع) { القضية 1: { تصميم عرض = LayoutInflater.from(context).inflate(R.layout.success_toast_layout, null, false); TextView text = (TextView) layout.findViewById(R.id.toastMessage); text.setText(msg); successToastView = (SuccessToast) layout.findViewById(R.id.successView); successToastView.startAnim(); text.setBackgroundResource(R.drawable.success_toast); text.setTextColor(Color.parseColor("#FFFFFF")); toast.setView(layout); break; } } toast.setDuration(length); toast.show(); } }
بهذا يمكن تنفيذ هذه الـ Toast المخصصة في ManiActivity.
حسنًا، انتهت.
كود المصدر للعبة:لعبة التلبيسعملية التنفيذ
gitHub:لعبة التلبيس.
هذا هو نهاية محتويات هذا المقال، آمل أن تكون قد ساعدتكم في التعلم، وأتمنى أن تدعموا تعليمات النطق بجد.
بيان: محتويات هذا المقال تم جمعها من الإنترنت، ويتمتع المالك الأصلي بحقوق النشر، ويتم جمع المحتويات من إسهامات المستخدمين عبر الإنترنت ويتم تحميلها بشكل مستقل، ويملك هذا الموقع حقوق الملكية، ولا يتم تعديل المحتويات بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية متعلقة بذلك. إذا وجدت محتوى يشتبه في انتهاك حقوق النسخ، فمرحبًا بمراسلتنا عبر البريد الإلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال '#' بـ '@') للإبلاغ، وقدم الدليل على الدليل، وسيتم حذف المحتوى المزعوم فورًا إذا تم التحقق من صحة الشكوى.