سنعمل في هذا المقال على بناء كاميرا لشاشة لمس في محرك الألعاب جودو كي يتمكن اللاعب من تحريك الكاميرا حول محورها وتكبير وتصغير وتدوير الكاميرا عن طريق اللمس.
تهيئة الكاميرا ثنائية البعد
افتح محرك الألعاب جودو وأنشئ مشروعك الأول، وابدأ بعقدة من النوع CameraD2
، ولجعلها حساسة للمس، سنضيف سكريبت يدير العملية، وذلك بالنقر عليها بالزر الأيمن للفأرة ثم اختيار "إلحاق نص برمجي attach script" ولنسمّه "TouchCameraController.gd".
ملاحظة أضفنا أيقونة إلى المشهد لكي نرى الكائن الذي يتحرك.
إعداد الكاميرا
نحتاج بداية إلى مجموعة من المتغيرات للتحكم بالكاميرا التي تمثلها في جودو العقدة Camera2D
. تمثل هذه المتغيرات سرعة الحركة المحورية وسرعة التكبير والتصغير، وسرعة الدوران، وأخرى للتحكم في إمكانية التحريك أو التكبير أو التدوير. وإضافة إلى ذلك، ننشئ متغيرات لتخزين حالة الكاميرا ومدخلات اللمس. إليك طريقة تعريف المتغيرات:
extends Camera2D @export var zoom_speed: float = 0.1 @export var pan_speed: float = 1.0 @export var rotation_speed: float = 1.0 @export var can_pan: bool @export var can_zoom: bool @export var can_rotate: bool var start_zoom: Vector2 var start_dist: float var touch_points: Dictionary = {} var start_angle: float var current_angle: float
قمنا في البداية بتوسيع الصنف Camera2D في Godot الذي يمثل كاميرا ثنائية الأبعاد 2D في جودو ثم حددنا مجموعة المتغيرات التي يمكن تعديلها وهي:
-
zoom_speed
: قيمة عددية تحدد سرعة عملية التكبير والتصغير للكاميرا. -
pan_speed
: قيمة عددية تحدد سرعة عملية التحريك الجانبي للكاميرا. -
rotation_speed
: قيمة عددية تحدد سرعة عملية تدوير الكاميرا. -
can_pan
: قيمة بوليانية تحدد إمكانية التحريك الجانبي للكاميرا. -
can_zoom
: قيمة بوليانية تحدد إمكانية التكبير أو التصغير للكاميرا. -
can_rotate
: قيمة بوليانية تحدد إمكانية تدوير الكاميرا.
ثم عرفنا المتغيرات التي ستخزن معلومات عن اللمس وهي:
-
start_zoom
لتخزين قيمة بداية عملية التكبير أو التصغير الحالي للكاميرا. -
start_dist
لتخزين المسافة بين نقاط اللمس عند بداية التكبير أو التصغير. -
touch_points
لتخزين مواقع نقاط اللمس على الشاشة لاستخدامها في حسابات التكبير والتدوير. -
start_angle
لتخزين زاوية بداية التدوير لحساب الزاوية المطلوبة للتدوير. -
current_angle
لتخزين الزاوية الحالية لعملية التدوير لتحديث تدوير العنصر المرئي بشكل مستمر.
تحريك الكاميرا حول محورها
لنبدأ اﻵن بتحريك الكاميرا حول محورها، وهي الحركة اﻷبسط التي تنفذها الكاميرا في المشهد. سنحتاج إلى وسيلة لترصّد بعض أحداث الدخل، لهذا سنتجاوز override الدالة (input(event_
للتحقق من أحداث اللمس touch والسحب drag على الشاشة والاستجابة لها بالشكل المناسب:
func _input(event): if event is InputEventScreenTouch: _handle_touch(event) elif event is InputEventScreenDrag: _handle_drag(event)
تخزّن الدالة (handle_touch(event_
موقع كل نقطة لُمست على الشاشة ضمن القاموس touch_points
وتستخدم دليل اللمس touch index كمفتاح، وهذا أساسي لتتبع المواقع التي تُلمس على الشاشة. كما سنضبط قيمة المتغير start_dist
على 0
إن كان عدد النقاط التي لُمست أقل من 2:
func _handle_touch(event: InputEventScreenTouch): if event.pressed: touch_points[event.index] = event.position else: touch_points.erase(event.index) if touch_points.size() < 2: start_dist = 0
بإمكاننا تحريك الكاميرا حول محورها بالاستفادة من نقطة لمس واحدة، وذلك باستخدام الدالة (handle_drag(event_
المعرفة كالتالي:
func _handle_drag(event: InputEventScreenDrag): touch_points[event.index] = event.position if touch_points.size() == 1 and can_pan: offset -= event.relative * pan_speed
إن شغّلت اللعبة على محاكي أندرويد سترى كيف تتحرك الكاميرا:
إضافة ميزة التكبير والتصغير
سنضيف اﻵن إمكانية التكبير والتصغير (تقريب وإبعاد)، لهذا سنعدّل الدالة (handle_touch(event_
كي نعالج حالة وجود نقطتي لمس والتي سنحسب فيها المسافة اﻷولية بينهما ونخزّنها:
func _handle_touch(event: InputEventScreenTouch): if event.pressed: touch_points[event.index] = event.position else: touch_points.erase(event.index) if touch_points.size() == 2: var touch_point_positions = touch_points.values() start_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) start_zoom = zoom start_dist = 0
نضيف بعد ذلك إمكانية التحكم بالتكبير والتصغير إلى الدالة handle_drag(event)_
، فعند وجود نقطتي لمس، نحسب المسافة الحالية بينهما وبناء عليها نضبط التكبير والتصغير:
func _handle_drag(event: InputEventScreenDrag): touch_points[event.index] = event.position # Handle 1 touch point if touch_points.size() == 1 and can_pan: offset -= event.relative * pan_speed # Handle 2 touch points elif touch_points.size() == 2 and can_zoom: var touch_point_positions = touch_points.values() var current_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) var zoom_factor = start_dist / current_dist zoom = start_zoom / zoom_factor limit_zoom(zoom) # This is about to be created!
نستخدم الدالة (limit_zoom(zoom
لمنع التكبير أو التصغير من تجاوز الحدود وسيقف التكبير أو التصغير عند حد معين:
func limit_zoom(new_zoom: Vector2): if new_zoom.x < 0.1: zoom.x = 0.1 if new_zoom.y < 0.1: zoom.y = 0.1 if new_zoom.x > 10: zoom.x = 10 if new_zoom.y > 10: zoom.y = 10
انقر على زر التشغيل لترى النتيجة:
إضافة الدوران
لنضف أخيرًا إمكانية تدوير الكاميرا، لهذا سنقيس الزاوية الأولية بين نقطتي اللمس من خلال الدالة handle_touch(event)_
:
func _handle_touch(event: InputEventScreenTouch): if event.pressed: touch_points[event.index] = event.position else: touch_points.erase(event.index) if touch_points.size() == 2: if touch_points.size() == 2: var touch_point_positions = touch_points.values() start_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) start_angle = get_angle(touch_point_positions[0], touch_point_positions[1]) start_zoom = zoom elif touch_points.size() < 2: start_dist = 0
نضيف بعد ذلك إمكانية التحكم بالدوران ضمن الدالة handle_drag(event)_
:
func _handle_drag(event: InputEventScreenDrag): touch_points[event.index] = event.position if touch_points.size() == 1: if can_pan: offset -= event.relative * pan_speed elif touch_points.size() == 2: var touch_point_positions = touch_points.values() var current_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) var current_angle = get_angle(touch_point_positions[0], touch_point_positions[1]) #this will be created below var zoom_factor = start_dist / current_dist if can_zoom: zoom = start_zoom / zoom_factor if can_rotate: rotation -= (current_angle - start_angle) * rotation_speed start_angle = current_angle # حدث الزاوية اﻷولية إلى الزاوية الحالية limit_zoom(zoom)
تٌستخدم الدالة (get_angle(p1, p2
لحساب الزاوية:
func get_angle(p1: Vector2, p2: Vector2) -> float: var delta = p2 - p1 return fmod((atan2(delta.y, delta.x) + PI), (2 * PI))
جرّب تدوير اﻷيقونة اﻵن!
السكريبت المكتمل
إليك الشيفرة الكاملة:
extends Camera2D @export var zoom_speed: float = 0.1 @export var pan_speed: float = 1.0 @export var rotation_speed: float = 1.0 @export var can_pan: bool @export var can_zoom: bool @export var can_rotate: bool var start_zoom: Vector2 var start_dist: float var touch_points: Dictionary = {} var start_angle: float var current_angle: float func _ready(): start_zoom = zoom func _input(event): if event is InputEventScreenTouch: _handle_touch(event) elif event is InputEventScreenDrag: _handle_drag(event) func _handle_touch(event: InputEventScreenTouch): if event.pressed: touch_points[event.index] = event.position else: touch_points.erase(event.index) if touch_points.size() == 2: var touch_point_positions = touch_points.values() start_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) start_angle = get_angle(touch_point_positions[0], touch_point_positions[1]) start_zoom = zoom elif touch_points.size() < 2: start_dist = 0 func _handle_drag(event: InputEventScreenDrag): touch_points[event.index] = event.position if touch_points.size() == 1: if can_pan: offset -= event.relative * pan_speed elif touch_points.size() == 2: var touch_point_positions = touch_points.values() var current_dist = touch_point_positions[0].distance_to(touch_point_positions[1]) var current_angle = get_angle(touch_point_positions[0], touch_point_positions[1]) var zoom_factor = start_dist / current_dist if can_zoom: zoom = start_zoom / zoom_factor if can_rotate: rotation -= (current_angle - start_angle) * rotation_speed start_angle = current_angle # Update the start_angle to the current_angle for the next drag event limit_zoom(zoom) func limit_zoom(new_zoom: Vector2): if new_zoom.x < 0.1: zoom.x = 0.1 if new_zoom.y < 0.1: zoom.y = 0.1 if new_zoom.x > 10: zoom.x = 10 if new_zoom.y > 10: zoom.y = 10 func get_angle(p1: Vector2, p2: Vector2) -> float: var delta = p2 - p1 return fmod((atan2(delta.y, delta.x) + PI), (2 * PI))
الخلاصة
صممنا في هذا المقال سكريبت كاميرا تتجاوب مع أفعال اللمس على الشاشة في محرك الألعاب جودو 4، ويمكنها التحرك حول محورها أو التكبير والتصغير أو الدوران. انتبه فقط إلى ضرورة ربط السكريبت بعقدة من النوع Camera2D
واستمتع بعملك!
ترجمة -وبتصرف- لمقال Building a touchscreen camera in Godot 4: A comprehensive guide
اقرأ أيضًا
- تشغيل محرك الألعاب جودو على بعض أنواع العتاد غير المدعوم
- تعرف على أشهر محركات الألعاب
- تعرف على أشهر لغات برمجة الألعاب
- مدخل إلى محرك الألعاب جودو
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.