مرحبا!
سأصف اليوم بالتفصيل كيف صنعت اللعبة على سطر الأوامر ، ومدى نجاحها.
من أين أتت الفكرة؟
لقد ألهمتني فكرة القيام بشيء بسيط للوهلة الأولى ، ولكن في نفس الوقت مثير للاهتمام من حيث التطوير. خطرت ببالي فكرة صنع لعبة في الكونسول ، وهي مثيرة للاهتمام من حيث التطوير ، وسيكون من المثير للاهتمام النظر إليها حتى من الخارج ، مثل هذه اللعبة.
محرك اللعبة
لذا ، لنبدأ بكيفية تنظيم اللعبة من الجذر ، وما هي فكرة عملها.
أولاً ، قررت كيفية عرض عالم اللعبة على وحدة التحكم. أدركت أنه من أجل عرض كائنات اللعبة ، نحتاج إلى قائمة تخزن قوائم أخرى تحتوي على رموز ، والتي يتم عرضها لاحقًا في ساحة اللعب في حلقة
for.
مع هذا الرمز:
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
هنا نرسم جميع الشخصيات من القائمة ، وننتقل إلى سطر جديد لرسم قائمة الشخصيات التالية.
هكذا يبدو المتغير الذي يخزن قوائم الرموز:
هنا نحصل على الفور على قرار بشأن كيفية عرض الكائنات في X و Y ، يمكننا الآن تحديد:
X - رمز في القائمة
Y - قائمة تحتوي على X
وبالتالي ، ارسم رمزًا ... سوف نستخدم هذا عند رسم كائنات اللعبة.
يمكننا محاولة رسم "كرة" في الملعب ، واستبدال الحرفين "O" بدلاً من X و Y.
للقيام بذلك ، اكتب الكود التالي:
import os
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
OUTPUT_IMAGE[4][6] = "O"
os.system("cls||clear")
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
وهكذا ، قمنا برسم كائن في ملعبنا. صحيح أن إحداثيات X و Y ليست كلاسيكية. أولاً ، نشير أولاً إلى Y ، ثم X ، وهو ما لا يتوافق تمامًا مع الكلاسيكيات ، وثانيًا ، يجب أن يزيد تنسيق Y من أجل رفع الكائن ، وفي حالتنا ، على العكس من ذلك ، يجب أن ينخفض.
الرسم البياني لـ X و Y في اللعبة:
يجب أيضًا مراعاة هذه الميزة لاحقًا عندما نقوم بتصادم الكائنات في وحدة التحكم.
يمكننا الآن محاولة تحريك كائننا عبر الملعب ، أي خلق الحركة.
سنحتاج إلى مسح وحدة التحكم لمحو الصورة القديمة لملعب اللعب.
سنفعل هذا بالأمر:
os.system("cls||clear")
أيضًا ، نحتاج إلى تجاوز المتغير
OUTPUT_IMAGEلمسح جميع الكائنات المرسومة مسبقًا في ميدان اللعب.
سنحتاج أيضًا إلى وضع كل هذا فيه
while True.
دعنا نضيف إلى
while Trueالوظيفة time.sleep(1)للحد من FPS.
وهكذا ، تم رسم الكود أمام أعيننا:
from time import sleep
from os import system
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
x = 0
y = 0
while True:
sleep(1)
system("cls||clear")
OUTPUT_IMAGE[y][x] = "O"
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
y += 1
x += 1
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
الآن لدينا القدرة على توزيع الأشياء عبر المجال.
صحيح أن هذه الأشياء بدائية للغاية ، وعلينا أن نتعلم كيفية رسم أشياء معقدة مثل اللاعبين والمنازل والطعام ... من
أجل رسم كائن معقد ، نحتاج إلى فهم ومعرفة كيفية رسم كائن من خلال تحديد X و Y مرة واحدة فقط.
لهذا نحتاج وظيفة تقبل صورة (رموز) ، X ، Y ؛
هيا بنا نقوم بذلك:
def SetImage(image: str, x: int, y: int):
pass
الآن نحن بحاجة إلى تنفيذه. للقيام بذلك ، تحتاج إلى تحديد كيفية رسم صورة تمتد على طول المحورين X و Y ، لقد توصلت إلى هذا:
ارسم كائنًا بتقسيمه إلى رموز ، وبمجرد مواجهة الحرف "\ n" ، أضف المحور
Y. المحور Y ، كما قلنا ، غير صحيح ، معكوسة ، لذلك نضيف إليها لخفض الكائن.
مثال على صورة مرسومة وفقًا لمبدأي:
image = " O\n'|'\n |"#
الآن دعنا نصف هذا في وظيفتنا:
def SetImage(x: int, y: int, image: str):
x_start = x
x = x
y = y
for word in image:
if word == "\n":
x = x_start
y += 1
else:
x += 1
try:
OUTPUT_IMAGE[y][x] = word
except IndexError:
break
دعنا نضيف
try: except()لتجنب الأخطاء إذا كان الكائن به X و Y صغير جدًا أو كبير جدًا.
x_startهذا هو X ، الذي نحتاج منه لبدء الرسم عند زيادة Y (
بالحرف "\ n") الآن يمكننا استخدام وظيفتنا ، وإسقاط X و Y فيها ، والصورة التي يجب رسمها:
الرمز
from time import sleep
from os import system
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
def SetImage(x: int, y: int, image: str):
x_start = x
x = x
y = y
for word in image:
if word == "\n":
x = x_start
y += 1
else:
x += 1
try:
OUTPUT_IMAGE[y][x] = word
except IndexError:
break
while True:
sleep(1)
system("cls||clear")
SetImage(x=3,y=4,image=" O\n'|'\n |")
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
وهذا ما حصلنا عليه:
تمامًا مثل الكرة التي رسمناها ، يمكن تحريكها على محوري X و Y.
الرمز
from time import sleep
from os import system
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
px = 0
py = 0
def SetImage(x: int, y: int, image: str):
x_start = x
x = x
y = y
for word in image:
if word == "\n":
x = x_start
y += 1
else:
x += 1
try:
OUTPUT_IMAGE[y][x] = word
except IndexError:
break
while True:
sleep(1)
system("cls||clear")
SetImage(x=px,y=py,image=" O\n'|'\n |")
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
px += 1
py += 1
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
والآن ، يتحرك اللاعب بالفعل حول الخريطة.
لقد فعلنا الكثير بالفعل ، هناك لاعب بالفعل ، وهناك بالفعل خريطة ، ويبدو أنه من الممكن بالفعل إنشاء لعبة ، لكن لا. نحتاج إلى وظيفة لحساب تصادمات الكائنات ، لأن أي نوع من الألعاب هو بدون تفاعلات الكائنات؟ اذا هيا بنا نبدأ.
أولاً ، نحتاج إلى عمل دالة للحصول على خط العرض والارتفاع للكائن من أجل حساب صندوق الوصول الخاص به.
لذلك ، قررت أن أجعل الوظيفة وفقًا للمنطق التالي:
X - صندوق الوصول للكائن في عرض X ، هذا هو أكبر عدد من الأحرف بين الأحرف "\ n" في الصورة
Y - صندوق النتائج في Y هو عدد الأحرف "\ n" في الصورة
بهذا المنطق ليس بالأمر الصعب قم بعمل وظيفة تلتقط صورة ، وتحسب كل الأحرف بين "\ n" لها ، وتختار أكبر عدد من الأحرف من هذا - يتم الحصول على خط العرض.
وإذا عدت الأحرف "\ n" ، كما كتبت بالفعل ، تحصل على الارتفاع.
تحولت الوظيفة على النحو التالي:
def GetSizeObject(img: str):
w = 0
weights = []
h = [word for word in img if word == "\n"]
for word in img:
if word == "\n":
weights.append(w)
w = 0
else:
w += 1
try:
return {"w": max(weights), "h":len(h)}
except ValueError:
return {"w": 0, "h":0}
ما سبب وجود ValueError إلا هنا؟
.
فلنرسم لاعبنا ونحسب عرضه وطوله.
رمز مع رسم وحساب خط العرض والارتفاع
from time import sleep
from os import system
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
px = 3
py = 3
def SetImage(x: int, y: int, image: str):
global OUTPUT_IMAGE
x_start = x
x = x
y = y
for word in image:
if word == "\n":
x = x_start
y += 1
else:
x += 1
try:
OUTPUT_IMAGE[y][x] = word
except IndexError:
break
def GetSizeObject(img: str):
w = 0
weights = []
h = [word for word in img if word == "\n"]
h.append(1)
for word in img:
if word == "\n":
weights.append(w)
w = 0
else:
w += 1
try:
return {"w": max(weights), "h":len(h)}
except ValueError:
return {"w": 0, "h":0}
player_image = " O\n'|'\n |"
def draw():
global OUTPUT_IMAGE
sleep(1)
system("cls||clear")
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
while True:
SetImage(x=px,y=py,image=player_image)
print(GetSizeObject(img=player_image))
draw()
الصيحة! لدينا وظيفة لحساب خط العرض والارتفاع ، وعلينا الآن عمل وظيفة لحساب مربع الوصول وتصادم الكائنات.
لنتذكر أن نظام الإحداثيات لدينا ليس نظامًا تقليديًا ، لذلك ، للأسف ، لا يمكننا استخدام الوظيفة التقليدية ، وعلينا أن نصنعها. للقيام بذلك ، قمت برسم مربعين على الرسم البياني يتصادمان ، ومن هذه الصورة يمكنك الخروج بشرط يتم من خلاله حساب التصادم.
لسهولة الفهم ، قمت برسم مربعات إصابة ، أي مربعات:
المنطق في الكلمات
x — X
y — Y
h —
w —
x2 — X
y2 — Y
h2 —
w2 —
:
X, Y,
:
X
x — X
y — Y
h —
w —
x2 — X
y2 — Y
h2 —
w2 —
:
y y2 - h2 + h y - h y2 + h2 - h
y2 y - h + h2 y2 - h2 y + h - h2
2 ?
2 , - / .
Y
Y
X, Y,
y — x, h — w.
:
x x2 - w2 + w x - w x2 + w2 - w
x2 x - w + w2 x2 - w2 x + w - w2
X
المنطق في الكود
, :
def IsClash(x: int, y: int, h: int, w: int,x2: int, y2: int, h2: int, w2: int):
if (y >= y2 - h2 + h and y - h <= y2 + h2 - h) or (y2 >= y - h + h2 and y2 - h2 <= y + h - h2):
if (x >= x2 - w2 + w and x - w <= x2 + w2 - w) or (x2 >= x - w + w2 and x2 - w2 <= x + w - w2):
return True
return False
True , False .
قمت برسم مكعب إضافي في ملعبنا بحيث يكون لدى اللاعب شخص يواجهه.
وجربت كيف تعمل وظيفة حساب التصادم.
هنا لاعب يلمس مكعبًا:
لكن لا يلمس:
رمز الاتصال
/ :
from time import sleep
from os import system
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
def SetImage(x: int, y: int, image: str):
global OUTPUT_IMAGE
x_start = x
x = x
y = y
for word in image:
if word == "\n":
x = x_start
y += 1
else:
x += 1
try:
OUTPUT_IMAGE[y][x] = word
except IndexError:
break
def GetSizeObject(img: str):
w = 0
weights = []
h = [word for word in img if word == "\n"]
h.append(1)
for word in img:
if word == "\n":
weights.append(w)
w = 0
else:
w += 1
try:
return {"w": max(weights), "h":len(h)}
except ValueError:
return {"w": 0, "h":0}
def IsClash(x: int, y: int, h: int, w: int,x2: int, y2: int, h2: int, w2: int):
if (y >= y2 - h2 + h and y - h <= y2 + h2 - h) or (y2 >= y - h + h2 and y2 - h2 <= y + h - h2):
if (x >= x2 - w2 + w and x - w <= x2 + w2 - w) or (x2 >= x - w + w2 and x2 - w2 <= x + w - w2):
return True
return False
player_image = " O\n'|'\n |"
cube_image = "____\n| |\n----"
cx = 5#
cy = 4 #
px = 10 #
py = 3#
def draw():
global OUTPUT_IMAGE
sleep(1)
system("cls||clear")
for line_words in OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
OUTPUT_IMAGE = [
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
[".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",],
]
while True:
SetImage(x=px,y=py,image=player_image)
SetImage(x=cx,y=cy,image=cube_image)
print("is clash: ",IsClash(
x=px,
x2=cx,
y=py,
y2=cy,
h=GetSizeObject(img=player_image)["h"],
h2=GetSizeObject(img=cube_image)["h"],
w=GetSizeObject(img=player_image)["w"],
w2=GetSizeObject(img=cube_image)["w"],
))
draw()
الآن لدينا جميع وظائف البداية للعبة ، في الواقع ، لقد كتبت لعبتي بناءً عليها.
لعبة
فكرة اللعبة هي كالتالي:
يوجد لاعب يظهر طعام حوله يضطر لجمعه حتى لا يموت. تحتوي اللعبة أيضًا على وظائف: التقاط الطعام ، ووضعه في المخزون ، وتناوله من المخزون ، ووضع عنصر من المخزون على الأرض ،
لقد بدأت بعمل حلقة لعبة في 3 أسطر ، الأمر بسيط
While True:
from time import sleep
while True:
sleep(0.1)
ثم اعتبرت أنه من الضروري إنشاء فئة يتم فيها تخزين جميع وظائف الكائنات المستقبلية. لذلك ، قمت بإنشاء ملف main.py ومجلد lib ، حيث وضعت ملف lib.py حيث كانت فئة اللعبة. أولئك. بدت ملفات اللعبة كما يلي:
+----game
| + --
| | -- main.py
| \ --lib
| +--lib.py -> class Game()
| \
|
+---
في المستقبل ، عملت بشكل أساسي مع فئة Game () ، في main.py لقد أطلقت عليها للتو ، وأنشأت كائنات البداية ، وبدأت اللعبة.
في فئة اللعبة ، قمت بعمل دالة run () تبدأ حلقة اللعبة. صنعت أيضًا وظيفة draw_all () ، وهي تمحو جميع الكائنات السابقة ، وترسم كائنات جديدة ، وتطبع في ساحة اللعب.
وهذا ما بدا عليه الفصل:
from time import sleep
class Game():
def __init__(self):
self.OUTPUT_IMAGE = [] #
def draw_all(self):
for line_words in self.OUTPUT_IMAGE:
for word in line_words:
print(word, end="")
print("\n", end="")
def run(self):
while True:
self.draw_all()
sleep(0.1)
وأضاف لي كل الوظائف الأساسية للنوع
set_image()، size_object()، is_clash()، وجميع أولئك الذين هم محرك اللعبة، والتي وصفتها أعلاه.
صنعت وظيفة جديدة
create_object()ومتغيرًا self.OBJECTS، وهي وظيفة create_object()أستخدمها لإنشاء كائنات ، تأخذ المعلمات img، name، x، y، up، rigid، data.
img- صورة الكائن -
nameاسم الكائن (منزل ، عشب ، ساكن ، طعام ، إلخ)
x- كائن X - كائن
yY
up- إذا كانت هذه المعلمة صحيحة ، فسيتم رسم الكائن فوق المشغل ، وإلا سيتداخل اللاعب معه
rigid- الصلابة ، لا يمكن للاعب تمر عبر هذا الكائن (لم يتم تنفيذه بعد)
data- البيانات الشخصية للكائن ، وخصائصه الشخصية
إنشاء كائن ()
:
def CreateObject(self,x: int, y: int, img: str, name: str = None, up: bool = False, rigid: bool = False, data: dict = {}):
size_object = self.GetSizeObject(img=img)
self.OBJECTS.append(
{"name": name,
"x": x,
"y": y,
"up": up,
"rigid": rigid,
"h":size_object["h"],
"w":size_object["w"],
"id":uuid4().hex,
"data":data,
"img": img}
)
في ذلك الوقت ، أضفت بالفعل لاعبًا ومنزلًا وعشبًا وقرويًا.
وقررت استخدام نفس المعامل في الكائن
up، واستخدامه في الكائن Home، أي بحيث يغطي المنزل اللاعب. للقيام بذلك ، قمت بعمل وظيفة CheckAll () ، مرت حلقة for عبر جميع الكائنات ، ورسمتها على الصورة الصادرة ، أي استخدم وظيفة SetImage (x: int ، y: int ، img: str) ، لتزويد X و Y للكائن ، وصورة.
وهكذا ، رسم أشياء يمكن للاعب أن يغلقها بنفسه. في نفس الدورة ، أعلنت قائمة
up_of_payer_objects، وإذا كان الكائن يحتوي على = صحيح ، فأنا أضفته إلى القائمة دون رسمه في الحقل. بعد ذلك قمت برسم اللاعب بنفسه ، وعندها فقط قمت بالمرور عبر حلقة for فوق الكائنات الموجودة في up_of_payer_objects ، وأرسمهم ، وبالتالي كانوا فوق اللاعب.
def CheckAll(self):
up_of_payer_objects = []
for object_now in range(len(self.OBJECTS)):
if object_now["up"]:
up_of_payer_objects.append(object_now)
continue
self.SetImage(x=object_now["x"],y=object_now["y"],image=object_now["img"])
ثم بدأت في تحريك اللاعب. لهذا ، قمت بإنشائه ككائن منفصل ، وهو غير موجود في القائمة
self.OBJECTS، ولكنه مخزن في متغير self.PLAYER.
جميع معلماتها حسب النوع
X، Y، img، itp يمكنك الحصول عليه باستخدام المفاتيح ، بمعنى آخر هو قاموس (ديكت) مع مثل هذا اللاعب والأشياء ، كان من الممكن بالفعل العمل والتحرك وحساب التصادمات. لقد بدأت بالانتقال.
لقد بدأت في إنشاء الحركة عن طريق إنشاء وظيفة CheckKeysObjects () ، المسؤولة عن تتبع ضغطات المفاتيح ، والتي أسميها في وظيفة CheckAll () في البداية
def CheckAll(self):
self.CheckKeysObjects()
....
لتتبع ضغطات المفاتيح ، استخدمت مكتبة لوحة المفاتيح ، و 4 متغيرات: وتبين أن كل شيء بسيط ، فنحن نتتبع المفاتيح ، وإذا تم الضغط عليها ، فإننا نصنع متغيرًا . في بداية الوظيفة ، نعلن عن جميع المتغيرات ، من أجل إعادة تعيين جميع النتائج السابقة ، وإلا فلن يتوقف اللاعب.
self.WALK_LEFT_PLAYER
self.WALK_RIGHT_PLAYER
self.WALK_UP_PLAYER
self.WALK_DOWN_PLAYER
dself.WALK_RIGHT_PLAYERTrue
False
CheckKeysObjects ()
def CheckKeysObjects(self):
# False,
self.WALK_LEFT_PLAYER = False
self.WALK_RIGHT_PLAYER = False
self.WALK_UP_PLAYER = False
self.WALK_DOWN_PLAYER = False
#
if keyboard.is_pressed("a"):
self.WALK_LEFT_PLAYER = True
elif keyboard.is_pressed("d"):
self.WALK_RIGHT_PLAYER = True
if keyboard.is_pressed("w"):
self.WALK_UP_PLAYER = True
elif keyboard.is_pressed("s"):
self.WALK_DOWN_PLAYER = True
بعد ذلك ، في الوظيفة ،
CheckAll()أتحقق من جميع المتغيرات المسؤولة عن الحركة ، وأكتشف أين يتحرك اللاعب.
إذا كان أي منها موجودًا
True، اكتشف أيهما ، وحرك الكائن في الاتجاه المعاكس.
رمز الحركة الناتج
def CheckAll(self):
self.CheckKeysObjects() # check moves
up_of_payer_objects = []
for object_now in range(len(self.OBJECTS)):
self.PLAYER["img"] = self.PLAYER["image_normal"]
if self.WALK_LEFT_PLAYER:
self.OBJECTS[object_now]["x"] += 1
elif self.WALK_RIGHT_PLAYER:
self.OBJECTS[object_now]["x"] -= 1
if self.WALK_UP_PLAYER:
self.OBJECTS[object_now]["y"] += 1
elif self.WALK_DOWN_PLAYER:
self.OBJECTS[object_now]["y"] -= 1
نعم ، نحن نحرك الأشياء في الاتجاه المعاكس من أجل خلق وهم الحركة. إذا انتقل اللاعب إلى اليمين ، فسيتم نقل جميع كائنات البيئة إلى اليسار.
ثم أضفت المزيد من العناصر البيئية ، وبدأت في إنتاج الطعام ، هدف اللاعب هو جمع الطعام حتى لا يموت.
للعد التنازلي لوقت تفرخ الطعام ، استخدمت
time.sleep()واحدة بسيطة ومكتبة threading- لتشغيل وظيفتين في نفس الوقت ، تفرخ الطعام وحلقة اللعبة الرئيسية. وظيفة تفرخ الطعام SpawnEat()هي مجرد وظيفة ، عند إطلاقها ، تنتج الطعام في أماكن عشوائية ، وتستدعي وظيفة لكل وحدة طعام CreateObject().
أيضًا ، بمجرد إنشاء وظيفة إنتاج الطعام ، قمت بعمل متغير المشغل
self.PLAYER["hungry"]، هذا هو جوعه ، في البداية يساوي 100 وحدة ، سأقللها إذا سار اللاعب وبذل طاقة (مثل الطاقة ، فهي ليست في اللعبة) أو زيادتها إذا أكل اللاعب شيئًا.
لقد صنعت أيضًا وظيفة
MinimizeHungry()، يتم استدعاؤها كل 5 ثوانٍ ، ويستغرق الأمر وحدتين من الجوع من اللاعب. فعلت هذا حتى يتحرك اللاعب ولا يقف ساكنًا.
أخيرًا ، في إحدى الوظائف
Eat()، يتم استدعاء هذه الوظيفة في سلسلة منفصلة من حلقة اللعبة. تتحقق مما إذا كان هناك الكثير من الطعام على الخريطة إذا كان هناك أكثر من 10 وحدات غذائية. لا تستدعي الوظيفة SpawnEat()إذا كانت أقل من 10 وحدات. ثم يدعو SpawnEat().
إليك كيف اتضح:
تأكل ()
def Eat(self):
while True:
sleep(4)
if len([i for i in self.OBJECTS if i["name"] == "meat"]) < 10:
self.SpawnEat()
sleep(1)
self.MinimizeHungry()
وظيفة
Start()لبدء الحلقة الرئيسية:
بداية ()
def Start(self):
while True:
self.CheckAll()
self.DrawAll()
sleep(0.01)
ووظيفة
run()تطلق اللعبة بأكملها.
يركض ()
def run(self):
proc1 = threading.Thread(target=self.Start)
proc1.start()
proc2 = threading.Thread(target=self.Eat)
proc2.start()
عملية الأكل نفسها ، نفذت ببساطة في وظيفة
CheckAll()و CheckKeysObjects(). Q CheckKeysObjects()لقد تحققت لمعرفة ما إذا كان اللاعب قد ضغط على الزر E. إذا ضغطت، ثم وضع متغير self.PRESS_Eفي True.
في الحلقة
CheckAll()، تحققت مما إذا كان الكائن الحالي في الحلقة forطعامًا ، وإذا لم يتحقق الطعام مما إذا كان اللاعب قد اصطدم به ، وإذا اصطدم ، فقم بفحص المتغير self.PRESS_E، وإذا كان Trueقد حذف الكائن ببساطة وزاد الجوع ، أي متغير self.PLAYER["hungry"].
هذا هو الحال في الكود
for object_now in range(len(self.OBJECTS)):
....
if self.OBJECTS[object_now]["name"] == "meat":
items_objects.append(object_now)
is_clash = self.IsClash(
x=self.OBJECTS[object_now]["x"],
y=self.OBJECTS[object_now]["y"],
h=self.OBJECTS[object_now]["h"],
w=self.OBJECTS[object_now]["w"],
x2=self.PLAYER["x"],
y2=self.PLAYER["y"],
h2=self.PLAYER["h"],
w2=self.PLAYER["w"],
)
if is_clash:
if self.PRESS_E:
try:
self.PLAYER["hungry"] += self.HUNGRUY_ADD
del self.OBJECTS[object_now]
break
except IndexError:
pass
سأقول مقدمًا ، سأحتاج إلى إعادة كتابة كل هذا عندما أقوم بإجراء الجرد
عمل الجرد
لذلك ، هذا صعب ، نحتاج إلى إجراء جرد.
تكمن الصعوبة في أن جميع الكائنات ستحتاج إلى عرضها وتخزينها وحفظها ووضع أشياء على الأرض.
لقد بدأت بإضافة مفتاح جديد إلى المشغل ، كان هناك
self.PLAYER["inventory"]4 خلايا مخزنة هناك ، مثل هذا:
"inventory":{
"0":{"status":"space","name":"#0", "minimize_image":"#0"},
"1":{"status":"space","name":"#1", "minimize_image":"#1"},
"2":{"status":"space","name":"#2", "minimize_image":"#2"},
"3":{"status":"space","name":"#3", "minimize_image":"#3"},
}
هي مجرد أرقام خلايا.
status- يخزن هذا المفتاح القيمة في حد ذاته ، خلية البويضة فارغة أم لا. إذا كانت فارغة ثم "مسافة" ، إذا كان هناك عنصر ، فسيتم تخزين اسم العنصر هناك.
name- يخزن اسم العنصر ، وسيتم استخدامه عندما يضع اللاعب العنصر.
minimize_image- هذه صورة صغيرة للعنصر الذي يتم عرضه في مخزون اللاعب.
بعد ذلك ، قمت بإجراء عمليات تحقق جديدة في عمليات التحقق الخاصة بنا
CheckKeysObjects()، عندما تنقر فوق Xالعنصر ، فسيتم طرحه على الأرض ، وأيضًا عند النقر فوق الزر ، Eسيتم استدعاء الوظيفة self.UseEat()، والتي سنقوم بتحليلها الآن.
لذا فإن الوظيفة
self.UseEat()هو عبارة عن ممر يمر عبر جميع خلايا الجرد بحثًا عن طعام ، وإذا وجد طعام ، يتم إزالته من الجرد ، وتضاف 10 وحدات للجوع. لإزالة عنصر من المخزون ، قمت بعمل وظيفة self.DestroyItem()يتم فيها توفير فهرس الخلية ، وتصبح الخلية بأكملها فارغة بشكل افتراضي وبدون أي شيء.
self.DestroyItem ()
def DestroyItem(self,index_item: str):
item = self.PLAYER["inventory"][index_item]
self.PLAYER["inventory"][index_item] = self.PLAYER["default_inventory_item"](index_item)
self.PLAYER["inventory_must_update"] = True
return item
self.CheckKeysObjects ()
def CheckKeysObjects(self):
self.WALK_LEFT_PLAYER = False
self.WALK_RIGHT_PLAYER = False
self.WALK_UP_PLAYER = False
self.WALK_DOWN_PLAYER = False
if key("a"):
self.WALK_LEFT_PLAYER = True
elif key("d"):
self.WALK_RIGHT_PLAYER = True
if key("w"):
self.WALK_UP_PLAYER = True
elif key("s"):
self.WALK_DOWN_PLAYER = True
if key("f"):
self.KEY_F = True
else:
self.KEY_F= False
if key("e"):
self.UseEat()
self.UseEat ()
def UseEat(self):
for inventory_item in range(len(self.PLAYER["inventory"])):
if self.PLAYER["inventory"][str(inventory_item)]["name"] == "meat":
if self.PLAYER["hungry"] + self.ADD_HUNGRY_COUNT < 100.0:
self.PLAYER["hungry"] += self.ADD_HUNGRY_COUNT
self.DestroyItem(index_item=str(inventory_item))
التالي هو وظيفة رمي جسم ما على الأرض.
ومع ذلك ، لا يوجد شيء معقد ، عند النقر على
Xالوظيفة تسمى self.QuitItem()، تمر الحلقة for عبر جميع خلايا المخزون ، وإذا ["status"]لم يكن المفتاح متساويًا "space"، فإننا نحذف هذه الخلية باستخدام الوظيفة التي تم النظر فيها مسبقًا self.DestroyItem()، وننشئ كائنًا بناءً على ما كان موجودًا في الخلية ، X و Y يضع اللاعب وكأنه رميه بجانبه.
self.Quititem ()
def QuitItem(self):
for inventory_item in range(len(self.PLAYER["inventory"])):
if self.PLAYER["inventory"][str(inventory_item)]["status"] != "space":
self.CreateObject(
img=self.PLAYER["inventory"][str(inventory_item)]["img"],
x=self.PLAYER["x"],
y=self.PLAYER["y"],
name=self.PLAYER["inventory"][str(inventory_item)]["name"],
data=self.PLAYER["inventory"][str(inventory_item)]["data"],
)
self.DestroyItem(index_item=str(inventory_item))
break
ومع ذلك ، هناك أشياء كثيرة لم أقلها كيف فعلت ، ت. ك. لم يكونوا الجزء الرئيسي من اللعبة ، وإن كان ذلك مثيرًا للاهتمام. على سبيل المثال ، رسائل حول إمكانية التقاط عنصر أم لا (عندما يكون المخزون ممتلئًا) ، أنني أضفت رسمًا متحركًا للمشي ، وأنني أنشأت مكتبة منفصلة للصور ، وأشياء أخرى.
هذا كل شئ؟
لا ، سأضيف شبكة عصبية إلى اللعبة ، باستخدام مكتبة كتبتها بلغة بايثون ،
سأقوم بتفاعل اللاعب مع الشخصيات غير القابلة للعب المجهزة بشبكة عصبية ، ومخطط
صغير ، ولكن من نوع ما ، وكذلك بعض الإمدادات للاعب ، مثل الدروع والطعام. العناصر ، والقدرة على البناء في كتل.
جرب اللعبة
يمكن تنزيله مجانًا من GitHub ، ما عليك سوى تشغيل Python3 ومكتبة لوحة المفاتيح . تحتاج إلى تشغيل الملف
main.py.
لعبة