1. قبل البدء
ملخّص
يعلّمك هذا الدرس التطبيقي حول الترميز كيفية استخدام البيانات من "منصة خرائط Google" لعرض الأماكن القريبة في الواقع المعزّز (AR) على Android.
المتطلبات الأساسية
- فهم أساسي لتطوير تطبيقات Android باستخدام "استوديو Android"
- الإلمام بلغة Kotlin
ما ستتعرّف عليه
- طلب إذن من المستخدم للوصول إلى كاميرا الجهاز وموقعه الجغرافي
- يمكنك الدمج مع Places API لجلب الأماكن القريبة من الموقع الجغرافي للجهاز.
- التكامل مع ARCore للعثور على أسطح مستوية أفقية حتى يمكن تثبيت الكائنات الافتراضية ووضعها في مساحة ثلاثية الأبعاد باستخدام Sceneform
- جمع معلومات حول موضع الجهاز في الفضاء باستخدام SensorManager واستخدام مكتبة أدوات "حزمة تطوير البرامج بالاستناد إلى بيانات خرائط Google للتطبيقات المتوافقة مع Android" لتحديد موضع العناصر الافتراضية في الاتجاه الصحيح
المتطلبات
- الإصدار 2020.3.1 من "استوديو Android" أو إصدار أحدث
- جهاز تطوير متوافق مع الإصدار 3.0 من OpenGL ES أو إصدار أحدث
- جهاز متوافق مع ARCore أو "محاكي Android" متوافق مع ARCore (يتم تقديم التعليمات في الخطوة التالية)
2. طريقة الإعداد
Android Studio
يستخدم هذا الدرس التطبيقي العملي الإصدار 10.0 من نظام التشغيل Android (المستوى 29 من واجهة برمجة التطبيقات) ويتطلّب تثبيت "خدمات Google Play" في Android Studio. لتثبيت كلتا التبعيتَين، أكمل الخطوات التالية:
- انتقِل إلى "أداة إدارة حِزم SDK" التي يمكنك الوصول إليها من خلال النقر على الأدوات > أداة إدارة حِزم SDK.
- تحقَّق مما إذا كان الإصدار 10.0 من نظام التشغيل Android مثبّتًا. إذا لم يكن مثبّتًا، ثبِّته من خلال وضع علامة في المربّع بجانب Android 10.0 (Q)، ثم انقر على حسنًا، ثم انقر على حسنًا مرة أخرى في مربّع الحوار الذي يظهر.
- أخيرًا، ثبِّت "خدمات Google Play" من خلال الانتقال إلى علامة التبويب أدوات حزمة تطوير البرامج (SDK)، ووضع علامة في مربّع الاختيار بجانب خدمات Google Play، والنقر على حسنًا، ثم النقر على حسنًا مرة أخرى في مربّع الحوار الذي يظهر**.**
واجهات برمجة التطبيقات المطلوبة
في الخطوة 3 من القسم التالي، فعِّل حزمة تطوير البرامج (SDK) لتطبيق "خرائط Google" على Android وPlaces API لهذا الدرس التطبيقي.
بدء استخدام "منصة خرائط Google"
إذا لم يسبق لك استخدام "منصة خرائط Google"، اتّبِع دليل "البدء باستخدام منصة خرائط Google" أو شاهِد قائمة تشغيل "البدء باستخدام منصة خرائط Google" لإكمال الخطوات التالية:
- أنشئ حساب فوترة.
- إنشاء مشروع
- فعِّل واجهات برمجة التطبيقات وحِزم تطوير البرامج (SDK) في "منصة خرائط Google" (المدرَجة في القسم السابق).
- أنشئ مفتاح واجهة برمجة تطبيقات.
اختياري: Android Emulator
إذا لم يكن لديك جهاز متوافق مع 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
: هذا الإذن مطلوب لكي يتمكّن تطبيقك من تنفيذ عمليات الشبكة واسترجاع البيانات عبر الإنترنت، مثل معلومات الأماكن من خلال Places API.android.permission.CAMERA
: يجب السماح بالوصول إلى الكاميرا حتى تتمكّن من استخدام كاميرا الجهاز لعرض العناصر في الواقع المعزّز.android.permission.ACCESS_FINE_LOCATION
—يجب منح الإذن بالوصول إلى الموقع الجغرافي لتتمكّن من البحث عن الأماكن القريبة من الموقع الجغرافي للجهاز.
بالنسبة إلى uses-feature
، الذي يحدّد ميزات الأجهزة التي يحتاجها هذا التطبيق، يتم الإعلان عمّا يلي:
- يجب أن يكون إصدار OpenGL ES 3.0.
- يجب استخدام جهاز متوافق مع 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" إلى حزمة تطوير البرامج (SDK) لخدمة "خرائط 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 للتطبيقات المتوافقة مع Android". سيتم استخدام الوظائف في هذه المكتبة لتحديد موضع العناصر الافتراضية في المساحة الحقيقية لاحقًا. -
com.google.ar.sceneform.ux:sceneform-ux
هي مكتبة Sceneform التي ستتيح لك عرض مشاهد ثلاثية الأبعاد واقعية بدون الحاجة إلى تعلُّم OpenGL. - تعتمد المعرّفات داخل معرّف المجموعة
com.squareup.retrofit2
على تبعيات Retrofit، ما يتيح لك كتابة برنامج HTTP بسرعة للتفاعل مع Places API.
بنية المشروع
ستجد هنا الحِزم والملفات التالية:
- **api:**تحتوي هذه الحزمة على فئات تُستخدَم للتفاعل مع Places API باستخدام Retrofit.
- **ar—**تحتوي هذه الحزمة على جميع الملفات ذات الصلة بـ ARCore.
- **model:**تحتوي هذه الحزمة على فئة بيانات واحدة
Place
، تُستخدَم لتغليف مكان واحد كما تعرضه Places API. - MainActivity.kt: هذا هو
Activity
الوحيد المضمّن في تطبيقك، والذي سيعرض خريطة وعرضًا من الكاميرا.
5- إعداد المشهد
تعمَّق في المكوّنات الأساسية للتطبيق بدءًا من عناصر الواقع المعزّز.
يحتوي MainActivity
على SupportMapFragment
، الذي سيتولّى عرض عنصر الخريطة، وفئة فرعية من ArFragment
—PlacesArFragment
—التي تتولّى عرض مشهد الواقع المعزّز.
إعداد الواقع المعزّز
بالإضافة إلى عرض مشهد الواقع المعزّز، ستتولّى PlacesArFragment
أيضًا طلب إذن استخدام الكاميرا من المستخدم إذا لم يتم منحه من قبل. يمكن أيضًا طلب أذونات إضافية من خلال إلغاء طريقة getAdditionalPermissions
. بما أنّه يجب أيضًا منح إذن تحديد الموقع الجغرافي، حدِّد ذلك وتجاهل طريقة getAdditionalPermissions
:
class PlacesArFragment : ArFragment() {
override fun getAdditionalPermissions(): Array<String> =
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
.toTypedArray()
}
تشغيلها
انتقِل إلى رمز الهيكل في الدليل starter
في Android Studio. إذا نقرت على تشغيل > تشغيل "التطبيق" من شريط الأدوات ونشرت التطبيق على جهازك أو المحاكي، سيُطلب منك أولاً تفعيل إذن تحديد الموقع الجغرافي والكاميرا. انقر على السماح، وسيظهر لك بعد ذلك عرض الكاميرا وعرض الخريطة جنبًا إلى جنب على النحو التالي:
رصد الطائرات
عند النظر إلى البيئة المحيطة بك باستخدام الكاميرا، قد تلاحظ نقطتَين بيضاوَين متراكبتَين على الأسطح الأفقية، مثل النقطتَين البيضاوَين على السجادة في هذه الصورة.
هذه النقاط البيضاء هي إرشادات يقدّمها ARCore للإشارة إلى أنّه تم رصد مستوى أفقي. تتيح لك هذه المستويات التي تم رصدها إنشاء ما يُعرف باسم "نقطة الارتكاز" لتتمكّن من وضع عناصر افتراضية في المساحة الحقيقية.
لمزيد من المعلومات حول ARCore وكيفية فهمه للبيئة المحيطة بك، يمكنك الاطّلاع على المفاهيم الأساسية.
6. الحصول على أماكن قريبة
بعد ذلك، عليك الوصول إلى الموقع الجغرافي الحالي للجهاز وعرضه، ثم استرداد الأماكن القريبة باستخدام Places API.
إعداد "خرائط Google"
مفتاح Google Maps Platform API
في السابق، أنشأت مفتاح Google Maps Platform API لتفعيل طلبات البحث في Places API واستخدام حزمة تطوير البرامج (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
من داخل تعبير lambda المقدَّم في 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. أماكن في الواقع المعزّز
حتى الآن، أجريت ما يلي:
- طلب أذونات الكاميرا والموقع الجغرافي من المستخدم عند تشغيل التطبيق لأول مرة
- إعداد ARCore لبدء تتبُّع المستويات الأفقية
- إعداد حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" باستخدام مفتاح واجهة برمجة التطبيقات
- تلقّي الموقع الجغرافي الحالي للجهاز
- استرداد الأماكن القريبة (المتنزّهات تحديدًا) باستخدام Places API
الخطوة المتبقية لإكمال هذا التمرين هي تحديد موضع الأماكن التي تسترجعها في الواقع المعزّز.
فهم المشهد
يستطيع ARCore فهم المشهد الواقعي من خلال كاميرا الجهاز عن طريق رصد نقاط مثيرة للاهتمام ومميزة تُعرف باسم نقاط الميزات في كل إطار صورة. عندما يتم تجميع نقاط الميزات هذه وتظهر على مستوى أفقي مشترك، مثل الطاولات والأرضيات، يمكن أن تتيح ARCore هذه الميزة للتطبيق كمستوى أفقي.
كما رأيت سابقًا، يساعد ARCore في توجيه المستخدم عند رصد مستوى مسطّح من خلال عرض نقاط بيضاء.
إضافة علامات ارتساء
بعد رصد مستوى أفقي، يمكنك إرفاق عنصر يُعرف باسم نقطة ارتساء. باستخدام نقطة ارتساء، يمكنك وضع عناصر افتراضية والتأكّد من أنّ هذه العناصر ستظل في الموضع نفسه في المساحة. يمكنك تعديل الرمز لإرفاق عنصر مرئي بعد رصد سطح مستوٍ.
في 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
.
تشغيلها
إذا شغّلت التطبيق مع التعديلات المذكورة أعلاه، ابحث من حولك إلى أن يتم رصد طائرة. انقر على النقاط البيضاء التي تشير إلى طائرة. بعد ذلك، ستظهر لك علامات على الخريطة لكل الحدائق الأقرب إليك. ومع ذلك، ستلاحظ أنّ الكائنات الافتراضية عالقة في نقطة الارتكاز التي تم إنشاؤها ولم يتم وضعها بالنسبة إلى أماكن هذه الحدائق في الفضاء.
في الخطوة الأخيرة، ستصحّح ذلك باستخدام مكتبة أدوات "حزمة تطوير البرامج بالاستناد إلى بيانات خرائط Google" لنظام التشغيل Android و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]
).
العنوان الكروي
بعد تحديد اتجاه الشمال، تتمثّل الخطوة التالية في تحديد الزاوية بين الشمال وكل مكان، ثم استخدام هذه المعلومات لتحديد موضع الأماكن في الاتجاه الصحيح في الواقع المعزّز.
لاحتساب العنوان، ستستخدم "مكتبة الأدوات المساعدة" في Maps SDK لنظام التشغيل 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- تهانينا
تهانينا على الوصول إلى هذه المرحلة.