كيفية تخزين واستلام البيانات في محرك Godot

Godot

في كل مرة احتاج فيها الى حفظ مكان اللاعب وتسجيل بياناته، فدائما ما يجب أن أبحث عن كيفية حفظ بياناته في ملف ما، مثل ملفات الجِسون (json)

ذلك لأنها ليست تقنية تُستخدم بكثرة، وليست لكل الألعاب. اي نعم من العادي البحث من جديد على مثل هذه التقنيات، ولكن لا بد من وجود مرجع يمكن الأعتماد عليه في هذا الشأن.

وحفظ بيانات اللاعب ليست فقط هو ما يهم، بل التعامل مع البيانات عامةً في محرك غودو Godot، فربما احتاج الى صناعة لعبة اسئلة واجوبة، بالتالي يجب استخدام ملف به تلك الاسئلة والاجوبة.

أو حتى أعدادات اللعبة نفسها مثل الاصوات وجودة الرسوميات، وأيضا نفس هذه النظام يُستعمل مع الخوادم (servers) في الألعاب متعددة اللاعبين (multi player).

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

التعامل مع البيانات

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

وأهمهم على الإطلاق هو نوع القواميس (dictionary)، ففي القواميس يمكن حفظ البيانات بأسلوب مهذب، فتصل اليها بسهولة من جديد عند الحاجة الى ذلك.

var my_dict = {
    “key”:”value”, # المفتاح وقيمته
    “number”:2, # مفتاح بقيمة رقمية
    “name”:”ahmed”, # مفتاح بقيمة نصية
    “the array”:[2, “ahmed”], # مفتاح بقيمة مصفوفة
    “dict_in_dict”:{ # مفتاح بقيمة قاموس
        “key”:”value”
    }
}

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

وقد تحدثت من قبل عن نظام التشغيل/التحميل التلقائي في المحرك، وهو يشبه هذا النظام قليلا، مع فارق أن البيانات المحفوظة، تُحفظ داخل ملف خارجي وليس ملف شيفرة (script) فهي ملفات بامتداد json او txt او csv.

وأهم مشكلة بداخل نظام التشغيل التلقائي، أن الشيفرة (script) كل متغيراتها ترجع لقيمتها الافتراضية عن اعادة تشغيل اللعبة، لكن بالنسبة لهذا النظام، فإن البيانات لا ترجع لقيمتها الافتراضية،

بالتالي ما يفعله النظام هو تسجيل/تعيين البيانات في قاموس او مصفوفة، ثم وضعها كما هي في ملف ما، وذلك الملف لا تتغير قيمة إلا لو قررت انت بنفسك تغير قيمة (سواء بكتابة تعليمات (code) او يدويا بفتح الملف).

لذا يمكنك الان عمل مشهد صغير جدا، وبه شيفرة فارغة، إلا من مُتغير من نوع القاموس، وبه أي بيانات تُحب.

ثم يأتي دور التعامل مع الملفات، وكيفية حفظ هذه البيانات في ملف ما.

تخزين البيانات في ملف

بالظبط يوجد نوعين اثنين من البيانات في نظام التخزين، الأول وهو القواميس {}، والثاني وهي المصفوفات []، الاولى يضع البيانات المطلوبة في ملفات النصوص مثل json, txt. cfg، الثاني يتعامل مع ملفات الجداول، مثل csv، prn.

القواميس > json

# دالتك الخاصة بالحفظ 
func save_data():
	# مسار الملف الذي تريد الحفظ فيه 
	var file_path = FileAccess.open("res://game_data.json", FileAccess.WRITE)
	# تحويل البيانات الى نوع json
	var json_string = JSON.stringify(data)
	# تخزين البيانات في الملف 
	file_path.store_line(json_string)
	pass

قم بكتابة اسم اي دالة تريد، ثم فيها انشئ متغيرا جديدا، والذي سيكون به الملف المطلوب لتخزين البيانات، حيث تستخدم الصنف FileAccess المسؤول عن التعامل مع الملفات، 

فيه المُعامل الأول خاص بمسار الملف ـ تاكد أن امتداده صحيح ـ والمعامل الثاني لتحديد طريقة التعامل مع هذه الملف، وفي هذه الحالة هي الكتابة. وان لم يتواجد الملف من قبل، فإن صنف FileAccess ينشئ ملفا جديدا لك. 

بعد ذلك تصنع متغيرا آخر، فيه تتحول البيانات التي تريدها (القاموس) الى نوع json، باستخدام الصنف JSON، والأمر stringify الخاص به، وتضع فيه متغير القاموس المطلوب، وهكذا تتحول البيانات الى نوع الجِسون.

ويجب فعل هذه الخطوة لأنه على سبيل المثال، ملفات الجِسون  لا تتعرف على قيم المتجهات (Vector) لذلك فإن الأمر stringify يغير نوعا إلى نوع آخر مناسب معها.

أخيرا تكتب التعليمة store_line بعد اسم المتغير الخاص بالملف، وبها تضع المتغير الخاصة ببيانات الجِسون، فهكذا تُخزن البيانات في ملف الجِسون الذي وضعت مساره.

المصفوفات (الجداول) > csv

بالنسبة لحفظ المصفوفات وتحويلها الى جداول، فأمرها اسهل بكثير من القواميس

# مصفوفة بداخلها مصفوفات اخرى بها القيم المطلوب حفظها 
var csv_data = [
	["name", "level", "room"], 
	["mohammed", 24, "house"]
	]
# اسم دالتك الخاصة بحفظ ملفات الجداول 
func save_csv():
	# مسار ملف الجداول 
	var file = FileAccess.open("res://csv_file.prn", FileAccess.WRITE)
	# المرور على المصفوفة وحفظ بياناتها في الملف مباشرة 
	# البيانات تُحفظ في شكل صفوف (يرجى فتح الملف)
	for row in csv_data:
		file.store_csv_line(row)
	pass

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

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

استلام البيانات من ملف

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

وفي العموم، اسلوب استلام البيانات أشبه بحفظها، فقط تُستعمل تعليمة خاصة بالاستلام، ولكن اولا يجب التاكد من أن الملف موجود بالفعل وإلا قد تحصل مشكلة.

قواميس > json

تبدأ أولا بالتأكد من أن الملف موجود بالفعل، باستخدام تعليمة file_exists من الصنف FileAccess، وإن لم تكن موجودة فوقتها تتوقف الدالة تماما باستعمال return، غير ذلك تُكمل الدالة لقراءة الملف.

وهذه المرة لا تستعمل الامر WRITE، بل الامر READ، لان المطلوب هو قراءة الملف وليس تسجيل البيانات فيه.

واخيرا تستعمل التعليمة get_as_text() الخاصة بالصنف Fileaccess، وهكذا تستلم القاموس، ولكن اي قيمة لا يتعامل معها الجِسون، تتحول مباشرة الى نص -مثل المتجهات.

# دالتك الخاصة باستلام البيانات
func load_data():
	# التأكد أن الملف بالفعل موجود 
	if not FileAccess.file_exists("res://game_data.json"):
		print("there is no file in this path")
		return
	# فتح الملف بأسلوب القراءة 
	var file_path = FileAccess.open("res://game_data.json", FileAccess.READ)
	# الحصول على بيانات الملف
	var new_data = file_path.get_as_text()
	# إرجاع بيانات الملف لمن استدعى الدالة
	return new_data

وفي نهاية الدالة احتفظت بالبيانات الجديدة في متغير new_data، ولكن يمكنك طباعته للتأكد أنها بالفعل البيانات المرغوب فيها.

المصفوفات (الجداول) > csv

استلام المصفوفات من الجداول قد يبدو معقدا قليلا، خاصة بسبب استعمال تعليمة الحلقات While وايضا تعليمة eof_reached() وحتى الجزء المتعلق بالوصول إلى آخر سطر في الجدول.

# اسم دالتك الخاصة بحفظ ملفات الجداول 
func load_csv():
	# المتغير الذي يُُخزن فيه بيانات الجدول
	var csv_data = []
	# التأكد أن الملف بالفعل موجود 
	if not FileAccess.file_exists("res://game_data.json"):
		print("there is no file in this path")
		return
	# قرائة ملف الجداول 
	var file = FileAccess.open("res://csv_file.prn", FileAccess.READ)
	# المرور على كل صف في الجدول 
	while not file.eof_reached():
		# الحصول على صف كامل وتخزينه
		var csv = file.get_csv_line()
		# إيقاف الحلقة لو وصلت للصف الاخير 
		if csv.size() <=1 : break
		csv_data.append(csv) # اضافة الصف الى المتغير 
	# إرجاع الجدول لمن طلبه
	return csv_data

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

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

ولكن لأنه يمر على كل الصفوف، فإن آخر صف ايضا يمر عليه، وهو صف فارغ، بالتالي أن حذفت التعليمة
if csv.size() <=1 : break ستجد في النهاية مصفوفة فارغة تماما.

والأمر eof_reached قيمته دائما صحيحة ما لم يصل المؤشر الى نهاية الجدول، بالتالي كان الحلقة تقول (طالما أن المؤشر ليس في نهاية المصفوفة، اكمل الدوران)

نقاط مهمة

المسارات في جهاز المستخدم

في كل الامثلة المطروحة كنت استعمل المسار res://، وهكذا تُحفظ الملفات او تستلمها من مجلد المشروع الخاص بك، ولكن ذلك ليس الأسلوب الأفضل.

الأسلوب السليم هو استعمال المسار user:// والذي يتعامل مع المجلد الشخصي الخاص بالمستخدم على جهازه الخاص، فتجده مثلا في نظام ويندوز في المسار : %APPDATA%\Godot\app_userdata\[project_name

تصدير هذه الملفات

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

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

الخلاصة

يعتمد نظام الحفظ واستلام البيانات عبر الملفات في محرك غودو godot على الصنف الاساسي FileAccess, والذي يوفر مجموعة كبيرة من الدوال لأجل ذلك.

منها دوال لحفظ القواميس وتحويلها لنوعية بيانات جِسون ومنها دوال تحفظ المصفوفات في جداول بيانات، وبالطبع توجد دوال لاستلام تلك البيانات من جديد.

ويمكن استعمال هذه الانظمة في حفظ بيانات اللاعب او اعدادات المستخدم الخاصة أو حتى التعامل مع البيانات الكبيرة نسبيا مثل ملف به عدد كبير من النصوص الخاصة بشخصيات اللعبة.

مصدر 1، مصدر 2، مصدر 3، مصدر 4

0 0 votes
Article Rating
Subscribe
نبّهني عن
guest

0 تعليقات
Inline Feedbacks
View all comments