عرض الأماكن المجاورة في الواقع المعزّز على نظام التشغيل Android (Kotlin)

1. قبل البدء

ملخص:

يعلّمك هذا الدرس التطبيقي حول كيفية استخدام البيانات من "منصة خرائط Google" لعرض الأماكن المجاورة في الواقع المعزّز (AR) على Android.

2344909dd9a52c60.png

المتطلّبات الأساسية

  • فهم آلية تطوير تطبيقات Android باستخدام "استوديو Android"
  • دراية بلغة Kotlin

ما ستتعرّف عليه

المتطلبات اللازمة

  • Android Studio 2020.3.1 أو إصدار أحدث
  • جهاز تطوير البرامج يتوافق مع OpenGL ES 3.0 أو إصدار أحدث
  • جهاز متوافق مع ARCore أو محاكي Android مُفعّل من ARCore (يتم تقديم التعليمات في الخطوة التالية)

2. الإعداد

استوديو Android

يستخدم هذا الدرس التطبيقي Android 10.0 (مستوى واجهة برمجة التطبيقات 29) ويتطلب تثبيت "خدمات Google Play" في "استوديو Android". لتثبيت كلتا الاعتمادات، أكمِل الخطوات التالية:

  1. انتقل إلى مدير حِزم تطوير البرامج (SDK) الذي يمكنك الوصول إليه عن طريق النقر على الأدوات &gt؛ مدير حزمة تطوير البرامج (SDK).

6c44a9cb9cf6c236.png

  1. تحقّق من تثبيت الإصدار 10.0 من نظام التشغيل Android. إذا لم يكن الأمر كذلك، يمكنك تثبيته من خلال وضع علامة في مربّع الاختيار بجانب Android 10.0 (Q)، ثم النقر على حسنًا، وأخيرًا النقر على حسنًا مرة أخرى في مربّع الحوار الذي يظهر.

368f17a974c75c73.png

  1. أخيرًا، ثبِّت خدمات Google Play من خلال الانتقال إلى علامة التبويب أدوات SDK، وحدّد مربع الاختيار بجوار خدمات Google Play، ثم انقر على حسنًا، ثم اختَر حسنًا مرة أخرى في مربّع الحوار الذي يظهر**.**

497a954b82242f4b.png

واجهات برمجة التطبيقات المطلوبة

في الخطوة 3 من القسم التالي، فعِّل SDK للخرائط لنظام التشغيل Android وواجهة برمجة تطبيقات الأماكن لهذا الدرس التطبيقي حول الترميز.

بدء استخدام "منصة خرائط Google"

إذا لم يسبق لك استخدام "منصة خرائط Google"، يمكنك اتّباع دليل بدء استخدام "منصة خرائط Google" أو مشاهدة "البدء في استخدام قائمة تشغيل منصة خرائط Google" لإكمال الخطوات التالية:

  1. أنشئ حساب فوترة.
  2. أنشئ مشروعًا.
  3. فعِّل واجهات برمجة تطبيقات ومنصة SDK لمنصة "خرائط Google" (المُدرَجة في القسم السابق).
  4. أنشئ مفتاح واجهة برمجة تطبيقات.

اختياري: محاكي Android

إذا لم يكن لديك جهاز متوافق مع ARCore، يمكنك بدلاً من ذلك استخدام "محاكي Android" لمحاكاة مشهد بتقنية الواقع المعزّز، وتزييف الموقع الجغرافي لجهازك. بما أنّك ستستخدم أيضًا Sceneform في هذا التدريب، ستحتاج أيضًا إلى التأكّد من اتّباع الخطوات الواردة ضمن "&المحاكي" لدعم Sceneform."

3- البدء بسرعة

للبدء في أسرع وقت ممكن، إليك بعض رموز البدء لمساعدتك في متابعة هذا الدرس التطبيقي حول الترميز. يمكنك على الفور الانتقال إلى الحل، ولكن إذا كنت تريد الاطّلاع على جميع الخطوات، يُرجى مواصلة القراءة.

يمكنك إنشاء نسخة طبق الأصل من المستودع في حال تثبيت git.

git clone https://github.com/googlecodelabs/display-nearby-places-ar-android.git

ويمكنك بدلاً من ذلك النقر على الزر أدناه لتنزيل رمز المصدر.

بعد الحصول على الرمز، يمكنك المتابعة وفتح المشروع الذي تم العثور عليه داخل دليل starter.

4. نظرة عامة حول المشروع

استكشِف الرمز الذي نزّلته من الخطوة السابقة. داخل هذا المستودع، من المفترض أن تجد وحدة واحدة باسم app، تحتوي على الحزمة com.google.codelabs.findnearbyplacesar.

ملف AndroidManifest.xml

تم الإعلان عن السمات التالية في ملف AndroidManifest.xml لتتمكّن من استخدام الميزات المطلوبة في هذا الدرس التطبيقي حول الترميز:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Sceneform requires OpenGL ES 3.0 or later. -->
<uses-feature
   android:glEsVersion="0x00030000"
   android:required="true" />

<!-- Indicates that app requires ARCore ("AR Required"). Ensures the app is visible only in the Google Play Store on devices that support ARCore. For "AR Optional" apps remove this line. -->
<uses-feature android:name="android.hardware.camera.ar" />

بالنسبة إلى uses-permission، والتي تحدد الأذونات التي يجب منحها للمستخدم قبل استخدام هذه الإمكانات، يتم الإعلان عن ما يلي:

  • android.permission.INTERNET: يهدف هذا الإجراء إلى السماح لتطبيقك بتنفيذ عمليات الشبكة وجلب البيانات على الإنترنت، مثل معلومات الأماكن عبر واجهة برمجة تطبيقات الأماكن.
  • android.permission.CAMERA: يجب الوصول إلى الكاميرا حتى تتمكّن من استخدام كاميرا الجهاز لعرض العناصر في الواقع المعزّز.
  • android.permission.ACCESS_FINE_LOCATION: يجب منح الإذن بالوصول إلى الموقع الجغرافي حتى تتمكّن من جلب الأماكن المجاورة ذات الصلة بالموقع الجغرافي للجهاز.

بالنسبة إلى uses-feature، والتي تحدد ميزات الأجهزة التي يحتاجها هذا التطبيق، يتم الإعلان عن ما يلي:

  • الإصدار 3.0 من OpenGL ES مطلوب.
  • يجب تشغيل جهاز متوافق مع ARCore.

بالإضافة إلى ذلك، تتم إضافة علامات البيانات الوصفية التالية ضمن عنصر التطبيق:

<application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  
  <!-- 
     Indicates that this app requires Google Play Services for AR ("AR Required") and causes
     the Google Play Store to download and install Google Play Services for AR along with
     the app. For an "AR Optional" app, specify "optional" instead of "required". 
  -->

  <meta-data
     android:name="com.google.ar.core"
     android:value="required" />

  <meta-data
     android:name="com.google.android.geo.API_KEY"
     android:value="@string/google_maps_key" />

  <!-- Additional elements here --> 

</application>

أول إدخال بيانات وصفية يشير إلى أن ARCore هو أحد متطلبات تشغيل هذا التطبيق، والثاني هو كيفية تقديم مفتاح واجهة برمجة التطبيقات لمنصّة Google Maps API إلى "خرائط Google" لنظام التشغيل Android.

build.gradle

في build.gradle، يتم تحديد التبعيات الإضافية التالية:

dependencies {
    // Maps & Location
    implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'com.google.android.gms:play-services-maps:17.0.0'
    implementation 'com.google.maps.android:maps-utils-ktx:1.7.0'

    // ARCore
    implementation "com.google.ar.sceneform.ux:sceneform-ux:1.15.0"

    // Retrofit
    implementation "com.squareup.retrofit2:retrofit:2.7.1"
    implementation "com.squareup.retrofit2:converter-gson:2.7.1"
}

في ما يلي وصف موجز لكل اعتمادية:

  • يتم استخدام المكتبات التي تحتوي على رقم تعريف المجموعة com.google.android.gms، وهي play-services-location وplay-services-maps، للوصول إلى معلومات الموقع الجغرافي للجهاز ووظائف الوصول المرتبطة بخدمة "خرائط Google".
  • com.google.maps.android:maps-utils-ktx هي مكتبة Kotlin (KTX) لـ "خرائط Google" SDK لمكتبة أدوات Android. سيتم استخدام الوظائف في هذه المكتبة لتحديد العناصر الافتراضية في وقت لاحق في المساحة الفعلية.
  • com.google.ar.sceneform.ux:sceneform-ux هي مكتبة Sceneform، ستتيح لك عرض مشاهد واقعية ثلاثية الأبعاد بدون الحاجة إلى تعلُّم OpenGL.
  • تتمثل تبعيات معرف المجموعة com.squareup.retrofit2 في تبعيات Retrofit التي تتيح لك كتابة برنامج HTTP بسرعة للتفاعل مع واجهة برمجة تطبيقات الأماكن.

بنية المشروع

ستجد هنا الحزم والملفات التالية:

  • **api—**تحتوي هذه الحزمة على فئات تُستخدم للتفاعل مع واجهة برمجة تطبيقات الأماكن باستخدام رجعي.
  • **ar—**تحتوي هذه الحزمة على جميع الملفات المتعلقة بـ ARCore.
  • **النموذج -**تحتوي هذه الحزمة على فئة بيانات واحدة Place تُستخدم لإرفاق مكان واحد كما تعرضه واجهة برمجة تطبيقات الأماكن.
  • MainActivity.kt - هذا هو Activity الوحيد الذي يتضمنه تطبيقك، والذي سيعرض خريطة وعرض الكاميرا.

5. إعداد المشهد

يمكنك الغوص في المكوّنات الأساسية للتطبيق، بدءًا من القطع في الواقع المعزّز.

يحتوي MainActivity على SupportMapFragment، والتي ستتعامل مع عرض عنصر الخريطة، وفئة فرعية من ArFragmentPlacesArFragment—وهي تتعامل مع عرض مشهد الواقع المعزّز.

إعداد الواقع المعزّز

وبصرف النظر عن عرض مشهد الواقع المعزّز، سيعالج PlacesArFragment أيضًا طلب إذن الكاميرا من المستخدم إذا لم يتم منحه من قبل. يمكن أيضًا طلب أذونات إضافية من خلال إلغاء طريقة getAdditionalPermissions. بما أنّك بحاجة أيضًا إلى منح إذن تحديد الموقع الجغرافي، حدِّد ذلك وتجاوز طريقة getAdditionalPermissions:

class PlacesArFragment : ArFragment() {

   override fun getAdditionalPermissions(): Array<String> =
       listOf(Manifest.permission.ACCESS_FINE_LOCATION)
           .toTypedArray()
}

تشغيلها

افتح رمز الهيكل العظمي في الدليل starter في "استوديو Android". إذا نقرت على تشغيل &gt؛ تشغيل "التطبيق&#39؛ من شريط الأدوات ونشر التطبيق على جهازك أو المحاكي، فسيُطلب منك أولاً تمكين إذن تحديد الموقع والكاميرا. انقر على سماح، وعند إجراء ذلك، من المفترض أن ترى عرض الكاميرا وعرض الخريطة جنبًا إلى جنب على النحو التالي:

e3e3073d5c86f427.png

رصد الطائرات

عند النظر حولك حول البيئة التي تتواجد فيها بالكاميرا، قد تلاحظ بعض النقاط البيضاء الموضوعة على الأسطح الأفقية، مثل النقاط البيضاء على السجادة في هذه الصورة.

2a9b6ea7dcb2e249.png

هذه النقاط البيضاء هي إرشادات مقدَّمة من ARCore للإشارة إلى أنه تم رصد طائرة أفقية. وتسمح لك هذه الطائرات التي تم اكتشافها بإنشاء ما يسمى "بنقطة اقتباس" وبحاجة إلى احتجاز ذلك، حتى تتمكن من وضع الكائنات الافتراضية في الفضاء الحقيقي.

لمزيد من المعلومات حول ARCore وكيفية التعرُّف على البيئة من حولك، اقرأ عن المفاهيم الأساسية المتعلقة به.

6- الحصول على الأماكن المجاورة

بعد ذلك، ستحتاج إلى الوصول إلى الموقع الجغرافي للجهاز وعرضه متبوعًا بجلب الأماكن المجاورة باستخدام واجهة برمجة تطبيقات الأماكن.

إعداد "خرائط Google"

مفتاح واجهة برمجة التطبيقات في "منصة خرائط Google"

في السابق، كان عليك إنشاء مفتاح واجهة برمجة التطبيقات في "منصة خرائط Google" لتفعيل طلب البحث في واجهة برمجة تطبيقات "الأماكن" وللتمكُّن من استخدام "SDK للخرائط" لنظام التشغيل Android. يمكنك فتح ملف gradle.properties واستبدال سلسلة "YOUR API KEY HERE" بمفتاح واجهة برمجة التطبيقات الذي أنشأته.

عرض الموقع الجغرافي للجهاز على الخريطة

بعد إضافة مفتاح واجهة برمجة التطبيقات، أضِف مساعدًا على الخريطة للمساعدة في توجيه المستخدمين في ما يتعلق بالخريطة. ولإجراء ذلك، انتقِل إلى طريقة setUpMaps وضمن مكالمة mapFragment.getMapAsync، اضبط googleMap.isMyLocationEnabled على true.. سيؤدي إجراء ذلك إلى عرض النقطة الزرقاء على الخريطة.

private fun setUpMaps() {
   mapFragment.getMapAsync { googleMap ->
       googleMap.isMyLocationEnabled = true
       // ...
   }
}

الحصول على الموقع الجغرافي الحالي

للاطّلاع على الموقع الجغرافي للجهاز، عليك استخدام صف FusedLocationProviderClient. ويتم حاليًا الحصول على مثال من هذا النوع باستخدام طريقة onCreate في MainActivity. لاستخدام هذا الكائن، املأ طريقة getCurrentLocation، التي تقبل وسيطة lambda حتى يمكن تمرير موقع جغرافي إلى المتصل بهذه الطريقة.

لإكمال هذه الطريقة، يمكنك الوصول إلى خاصية lastLocation لكائن FusedLocationProviderClient متبوعًا بإضافة addOnSuccessListener على النحو التالي:

fusedLocationClient.lastLocation.addOnSuccessListener { location ->
    currentLocation = location
    onSuccess(location)
}.addOnFailureListener {
    Log.e(TAG, "Could not get location")
}

يتم استدعاء طريقة getCurrentLocation من داخل لامدا المتوفرة في getMapAsync في طريقة setUpMaps التي يتم جلب الأماكن المجاورة منها.

بدء الاتصال بأماكن الشبكة

في استدعاء طريقة getNearbyPlaces، تجدر الإشارة إلى أنه يتم تمرير المعلمات التالية إلى الطريقة placesServices.nearbyPlaces، وهي مفتاح واجهة برمجة تطبيقات، وموقع الجهاز، ونطاق جغرافي بالأمتار (تم ضبطه على 2 كيلومتر)، ونوع مكان (محدّد حاليًا على park).

val apiKey = "YOUR API KEY"
placesService.nearbyPlaces(
   apiKey = apiKey,
   location = "${location.latitude},${location.longitude}",
   radiusInMeters = 2000,
   placeType = "park"
)

لإكمال استدعاء الشبكة، يمكنك المتابعة وتمرير مفتاح واجهة برمجة التطبيقات الذي حددته في ملف gradle.properties. يتم تحديد مقتطف الرمز التالي في ملف build.gradle ضمن android > defaultConfig:

android {
   defaultConfig {
       resValue "string", "google_maps_key", (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
   }
}

سيؤدي هذا إلى إتاحة قيمة مورد السلسلة google_maps_key في وقت الإصدار.

لإكمال استدعاء الشبكة، يمكنك ببساطة قراءة مورد السلسلة هذا عبر getString على الكائن Context.

val apiKey = this.getString(R.string.google_maps_key)

7- الأماكن في الواقع المعزّز

لقد نجحت حتى الآن في إجراء ما يلي:

  1. إذا طلبت المستخدم أذونات الكاميرا والموقع الجغرافي عند تشغيل التطبيق لأول مرة
  2. إعداد ARCore لبدء تتبع الطائرات الأفقية
  3. إعداد SDK للخرائط باستخدام مفتاح واجهة برمجة التطبيقات
  4. تعرّف على الموقع الجغرافي الحالي للجهاز
  5. تم جلب الأماكن المجاورة (تحديدًا المتنزهات) باستخدام واجهة برمجة تطبيقات الأماكن

الخطوة المتبقية لإكمال هذا التمرين هي وضع الأماكن التي تجلبها في الواقع المعزّز.

فهم المشهد

بإمكان ARCore فهم المشهد الحقيقي من خلال كاميرا الجهاز، وذلك عن طريق رصد نقاط شيّقة ومميّزة تُسمّى نقاط الميزات في كل إطار صورة. عند تجميع نقاط العناصر هذه وظهورها على مستوى أفقي مشترك، مثل الجداول والأرضيات، يمكن أن تتيح ARCore هذه الميزة للتطبيق كطائرة أفقية.

كما رأيت من قبل، تساعد ARCore في توجيه المستخدم عند اكتشاف طائرة من خلال عرض نقاط بيضاء.

2a9b6ea7dcb2e249.png

إضافة علامات الارتساء

وبعد رصد طائرة، يصبح بإمكانك إرفاق عنصر يُسمى مُثبّت. ومن خلال علامة ارتساء، يمكنك وضع كائنات افتراضية وضمان أن تظل هذه الكائنات في الموضع نفسه في الفضاء. كَمِّلْ وِعَدِّلِ الرَّمْزْ لِرَفْعْ رَمْزْ بَعْدْ تَتَحَقَّقْ طَيَرَانْ.

في setUpAr، يتم إرفاق OnTapArPlaneListener بجهاز PlacesArFragment. يتم تفعيل هذا المستمع عند النقر على طائرة في مشهد الواقع المعزّز. أثناء هذه المكالمة، يمكنك إنشاء Anchor وAnchorNode من HitResult المتوفّرة في المستمع على النحو التالي:

arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
   val anchor = hitResult.createAnchor()
   anchorNode = AnchorNode(anchor)
   anchorNode?.setParent(arFragment.arSceneView.scene)
   addPlaces(anchorNode!!)
}

AnchorNode سيتم إرفاق كائنات العُقد الفرعية—PlaceNode مثيلات—في المشهد الذي يتم التعامل معه في استدعاء طريقة addPlaces.

التشغيل

وفي حال تشغيل التطبيق مع تطبيق التعديلات المذكورة أعلاه، يمكنك النظر من حولك حتى يتم اكتشاف طائرة. أَرْجُو الْمُتَابْعَة وِالضَّغْطْ عَلَى النُّقَاطِ الْبِيضَة الْلِّي عَلَشَانْ تِشْرَفْ طَائِرَة. أثناء تنفيذ ذلك، يجب أن ترى الآن العلامات على الخريطة لجميع المتنزهات القريبة من حولك. ومع ذلك، إذا لاحظت ذلك، ستكون الكائنات الافتراضية عالقة في علامة الارتساء التي تم إنشاؤها ولا يتم وضعها بالنسبة إلى مكان هذه المتنزّهات في الفضاء.

f93eb87c98a0098d.png

بالنسبة إلى الخطوة الأخيرة، سيتم تصحيح هذا الخطأ باستخدام Maps SDK for Android Utility Library وSensorManager على الجهاز.

8- مكان الأماكن

لتتمكن من وضع رمز المكان الافتراضي في الواقع المعزّز على عنوان دقيق، ستحتاج إلى معلومة واحدة:

  • حيث الشمال صحيح
  • الزاوية بين الشمال وكل مكان

تحديد الشمال

يمكن تحديد الشمال باستخدام أجهزة استشعار الموضع (المغناطيسية الأرضية ومقياس التسارع) المتاحة على الجهاز. باستخدام هذين المستشعرين، يمكنك جمع معلومات في الوقت الفعلي عن موضع الجهاز في الفضاء. لمزيد من المعلومات حول أجهزة استشعار الموضع، اقرأ احتساب اتجاه الجهاز.

للوصول إلى أجهزة الاستشعار هذه، يجب الحصول على SensorManager متبوعًا بتسجيل SensorEventListener على أجهزة الاستشعار هذه. سبق أن تم تنفيذ هذه الخطوات بالنيابة عنك في طرق دورة حياة MainActivity:

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   // ...
   sensorManager = getSystemService()!!
   // ...
}

override fun onResume() {
   super.onResume()
   sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also {
       sensorManager.registerListener(
           this,
           it,
           SensorManager.SENSOR_DELAY_NORMAL
       )
   }
   sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also {
       sensorManager.registerListener(
           this,
           it,
           SensorManager.SENSOR_DELAY_NORMAL
       )
   }
}

override fun onPause() {
   super.onPause()
   sensorManager.unregisterListener(this)
}

في الطريقة onSensorChanged، يتم توفير كائن SensorEvent، والذي يحتوي على تفاصيل حول جهاز الاستشعار المعيّن أثناء تغييره بمرور الوقت. يُرجى إضافة الرمز التالي إلى هذه الطريقة:

override fun onSensorChanged(event: SensorEvent?) {
   if (event == null) {
       return
   }
   if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
       System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
   } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
       System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
   }

   // Update rotation matrix, which is needed to update orientation angles.
   SensorManager.getRotationMatrix(
       rotationMatrix,
       null,
       accelerometerReading,
       magnetometerReading
   )
   SensorManager.getOrientation(rotationMatrix, orientationAngles)
}

ويتحقّق الرمز أعلاه من نوع المستشعر، وتحدّث القياس المناسب لجهاز القياس حسب إما مقياس التسارع أو مقياس المغناطيسية. باستخدام قراءات جهاز الاستشعار هذه، يمكن الآن تحديد قيمة عدد الدرجات من الشمال بالنسبة إلى الجهاز (أي قيمة orientationAngles[0]).

عنوان كروي

الآن وقد تم تحديد الشمال، تتمثل الخطوة التالية في تحديد الزاوية بين الشمال وكل مكان متبوعًا باستخدام تلك المعلومات لوضع الأماكن في العنوان الصحيح في الواقع المعزّز.

لاحتساب العنوان، عليك استخدام "حزمة تطوير البرامج (SDK)" لخدمة "خرائط Google" لمكتبة أدوات مساعدة Android، والتي تحتوي على مجموعة من الوظائف المساعدة لحوسبة المسافات والعناوين من خلال الهندسة الهندسية الكروية. لمزيد من المعلومات، يُرجى الاطّلاع على نظرة عامة على المكتبة.

بعد ذلك، ستستخدم طريقة sphericalHeading في مكتبة الأدوات، والتي تحسب العنوان/الحاجة بين عنصرَي LatLng. هذه المعلومات مطلوبة داخل طريقة getPositionVector الموضَّحة في Place.kt. ستؤدي هذه الطريقة إلى عرض عنصر Vector3، وسيتم استخدامه بعد ذلك بواسطة كل PlaceNode كموضع محلي في مساحة الواقع المعزّز.

احرص على استبدال تعريف العنوان بهذه الطريقة بما يلي:

val heading = latLng.sphericalHeading(placeLatLng)

ومن المفترض أن يؤدي ذلك إلى تعريف الطريقة التالية:

fun Place.getPositionVector(azimuth: Float, latLng: LatLng): Vector3 {
   val placeLatLng = this.geometry.location.latLng
   val heading = latLng.sphericalHeading(placeLatLng)
   val r = -2f
   val x = r * sin(azimuth + heading).toFloat()
   val y = 1f
   val z = r * cos(azimuth + heading).toFloat()
   return Vector3(x, y, z)
}

الموضع المحلي

الخطوة الأخيرة لتوجيه الأماكن بشكل صحيح في الواقع المعزّز هي استخدام نتيجة getPositionVector عند إضافة عناصر PlaceNode إلى المشهد. يمكنك الانتقال إلى addPlaces في MainActivity، أسفل السطر الذي يتم تحديد الوالد فيه على كل placeNode (أسفل placeNode.setParent(anchorNode) مباشرةً). يمكنك ضبط localPosition من placeNode على نتيجة الاتصال بالرقم getPositionVector كما يلي:

val placeNode = PlaceNode(this, place)
placeNode.setParent(anchorNode)
placeNode.localPosition = place.getPositionVector(orientationAngles[0], currentLocation.latLng)

بشكل تلقائي، تضبط الطريقة getPositionVector المسافة y للعقدة على متر واحد كما هو محدّد من خلال القيمة y في الطريقة getPositionVector. إذا كنت تريد ضبط هذه المسافة، قُل مثلاً لمسافة مترَين وعدِّل تلك القيمة حسب الحاجة.

بعد هذا التغيير، يجب أن تكون عناصر PlaceNode المُضافة موجّهة الآن في العنوان الصحيح. وِبَعْدْ كِدَهْ، مُمْكِنِ الْمُتَابْعَة وِتَشْغِيلِ التَّطْبِيقْ عَلَشَانْ تِعْرَفِي النَّتِيجَة!

9- تهانينا

تهانينا على تحقيق هذا الإنجاز.

مزيد من المعلومات