اذهب إلى المحتوى

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

يمكنك مطالعة المقالات ضمن السلسلة:

  1. بناء لعبة نرد بسيطة بلغة بايثون.
  2. بناء لعبة رسومية باستخدام بايثون ووحدة الألعاب PyGame.
  3. إضافة لاعب إلى اللعبة المطورة باستخدام بايثون و Pygame.
  4. تحريك شخصية اللعبة باستخدام PyGame.
  5. إضافة شخصية العدو للعبة.
  6. إضافة المنصات إلى لعبة بايثون باستخدام الوحدة Pygame.
  7. محاكاة أثر الجاذبية في لعبة بايثون.
  8. إضافة خاصية القفز والركض إلى لعبة بايثون.
  9. إضافة الجوائز إلى اللعبة المطورة بلغة بايثون.
  10. تسجيل نتائج اللعبة المطورة بلغة بايثون وعرضها على الشاشة.
  11. إضافة آليات القذف إلى اللعبة المطورة بلغة بايثون.

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

عرض النتائج في Pygame

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

قراءة التوثيقات

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

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

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

فهم رموز التوثيق الفني

يبدأ توثيق وحدة الخط بالدالة ‎pygame.font.init‎(‎)‎ ويصفها التوثيق بأنها دالة التهيئة للوحدة، تُستدعى تلقائيًا بواسطة ()pygame.init المستدعاة أساسًا في برنامج اللعبة، واستخدامها شبيه بما تعلمته خلال السلسلة، إذ ستتمكن من استخدام دوالها وكتابة النتيجة على الشاشة بقراءة بسيطة للتوثيق ومراجعة لما تعلمته.

ولو استمريت باستعراض الوحدات في توثيقات Pygame ستصادف الوحدة Pygame.freetype ومن الاسم يتضح ارتباطها بحالتنا وهي أفضل من وحدة الخط إذ يصفها التوثيق بأنها:

اقتباس

بديل وحدة الخط الخاصة بتحميل الخطوط وعرضها على الشاشة، وهي تتضمن وظائف الوحدة الأصلية جميعها مع العديد من الميزات الإضافية الجديدة.

وفي صفحة التوثيق نفسها المخصصة للوحدة ستجد بعض الأمثلة على طريقة استخدامها ومنها:

import pygame
import pygame.freetype

السطر موجود لدينا في برنامج اللعبة وما نحتاجه هو السطر الثاني، أضفه إذًا لمجموعة تعليمات import لتصبح على الشكل التالي:

import pygame
import sys
import os
import pygame.freetype

استخدام الخطوط في Pygame

استنادًا للتوثيق تعرض الوحدتان النصوص على الشاشة باستعمال الخطوط الإفتراضية في Pygame أو أي خطوط أخرى تزودها بها، وستجد ضمن توثيق الوحدة pygame.freetype التوصيف الفني للدالة التالية:

pygame.freetype.Font
# إنشاء خط جديد انطلاقًا من أحد ملفات الخطوط المدعومة

Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font

pygame.freetype.Font.name
# اسم ملف الخط

pygame.freetype.Font.path
# مسار ملف الخط

pygame.freetype.Font.size
# حجم الخط الافتراضي المستخدم في العرض

وهي مسؤولة عن إنشاء كائن Object الخط في Pygame ومواصفاته ولو دققت فيها ستجدها مشابهة لتعليمات إنشاء كائنات اللعبة مثل الأبطال والأعداء فبدلًا من صورة الشخصية ستحدد هنا ملف الخط وبمجرد توفره يمكنك إنشاء كائن الخط باستخدام الدالة السابقة pygame.freetype.Font ومن ثم استدعائه للعرض على الشاشة.

إدارة الخط بصفته أحد أصول اللعبة

لتضمن عمل لعبتك بصورةٍ جيدة عليك تضمن الخط الذي تعتمده ضمن ملفات اللعبة فمجموعات الخطوط تختلف من حاسبٍ لآخر، لذا أنشئ مجلدًا خاصًا بالخطوط في المجلد الأب للعبتك تمامًا مثل مجلد الصور وضع فيه ملفات الخطوط التي تستخدمها.

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

وفيما يلي قائمة ببعض المواقع التي توفر خطوطًا مجانية واستخدامها قانوني يمكنك الاستفادة منها:

حمّل الخط الذي أعجبك من هذه المواقع على شكل ملف مضغوط zip أو tar وفك ضغطه لاستخراج ملف الخط، ويكون عادةً بصيغة ttf. أو otf. ومن ثم ضعه في مجلد الخطوط الخاصة باللعبة.

لا يوجد أي حاجة لتثبيت الخط في نظام التشغيل لديك بل يكفي وجوده في مجلد اللعبة لتستخدمه Pygame، وفي حال تضمن اسم الملف رموزًا أو فراغات أزلها وعدّل الاسم، ويفضل لو تختر له اسمًا بسيطًا ومختصرًا لتكتبه بسهولة في التعليمات البرمجية.

تعليمات الخط في Pygame

بناءً على توثيق الدالة pygame.freetype.Font يمكنك إنشاء كائن الخط عبر تحديد مسار ملف الخط المرغوب على الأقل المدخلات الأخرى فهي اختيارية وليست ملزمة.

Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font

أنشئ متغيرًا جديدًا اسمه myfont وأسند له خرج الدالة Font المذكورة وفق التعليمات الآتية وملف الخط الذي اعتمدنا عليه هنا هو amazdoom.ttf على سبيل المثال.

font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"fonts","amazdoom.ttf")
font_size = tx
pygame.freetype.init()
myfont = pygame.freetype.Font(font_path, font_size)

عرض النص على الشاشة في Pygame

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

def stats(score,health):
    myfont.render_to(world, (4, 4), "Score:"+str(score), BLACK, None, size=64)
    myfont.render_to(world, (4, 72), "Health:"+str(health), BLACK, None, size=64)

والآن استدعيها في حلقة التكرار الرئيسية:

    stats(player.score,player.health) # draw text

إذا شغلت اللعبة الآن ستحصل على خطأ فهي ما زالت بحاجة لبعض التعديلات.

تفسير الأخطاء

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

عند تشغيل اللعبة في هذه المرحلة ستحصل على هذا الخطأ:

Traceback (most recent call last):
  File "/home/tux/PycharmProjects/game_001/main.py", line 41, in <module>
    font_size = tx
NameError: name 'tx' is not defined

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

لو رجعت إلى برنامج اللعبة وتفقدت تعريف المتغير tx ستجده معرفًا مع المغير ty في مقطع الإعدادات ضمن البرنامج وهو يأتي بعد السطر 41 في تسلسل الأسطر.

اتضحت الصورة الآن علينا نقل تعريف المتغير إلى موضعٍ آخر ضمن البرنامج ترتيبه يسبق السطر 41 وبذلك يمرّ عليه بايثون قبل الوصول لهذا السطر ويُحل الخطأ.

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

تشغيل اللعبة

شغل اللعبة وتفقد نجاح العملية.

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

pygame-score

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

لا يعطل هذا النوع من الأخطاء عمل البرنامج فهو ليس من الأخطاء "القاتلة" إنما يعد من المشكلات البسيطة التي تعطي نتائج غير منطقية أو تزعج المستخدم.

إصلاح عداد صحة البطل

المشكلة في عداد صحة اللاعب أن نقاطه تتناقص مع كل نبضة ساعة يكون فيها العدو والبطل في حالة تصادم، وهذا غير عادلة طبعًا بالعدو بطيء الحركة سينقص صحة اللاعب بمقدار 200- نقطة أو ربما أكثر، يمكنك بكل بساطة زيادة رصيد الصحة الابتدائي للاعبك إلى رقم كبير نسبيًا مثل 10000 سيخفف هذا من أثر المشكلة لكنه لا يعد حلًا مثاليًا.

فالحل الأفضل يكتشف حادثتين عوضًا عن واحدة، فلن يكتشف التصادم فقط إنما أيضًا انتهاء التصادم.

عرّف المتغير الموجود في السطر الأخير ضمن صنف اللاعب ليمثل حالة التصادم بين البطل والعدو:

        self.frame = 0
        self.health = 10
        self.damage = 0

والآن استبدل كتلة التعليمات التالية في دالة التحديث update:

        for enemy in enemy_hit_list:
            self.health -= 1
            #print(self.health)

بهذه الكتلة:

       if self.damage == 0:
            for enemy in enemy_hit_list:
                if not self.rect.contains(enemy):
                    self.damage = self.rect.colliderect(enemy)

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

الدالة الأولى هي self.rect.contains مهمتها معرفة فيما إذا كان العدو متواجدًا داخل المربع المحيط باللاعب في لحظة التنفيذ. والدالة الثانية self.rect.colliderect تعطي المتغير self.damage القيمة 1 إذا كانت نتيجة الدالة الأولى محققة أي أن العدو داخل المربع المحيط بالبطل بغض النظر عن عدد مرات تحققها.

وبدءًا من الآن سيُعدّ التصادم بين العدو والبطل لمدة ثلاث ثواني حادث تصادم واحد فقط من وجهة نظر Pygame ويخصم عنه مرة واحدة فقط.

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

اكتب أخيرًا التعليمات التالية لتكتشف انتهاء حالة التصادم أو التلامس بين اللاعب والعدو وعندها فقط يطرح البرنامج نقطة واحدة من رصيد صحة اللاعب:

        if self.damage == 1:
            idx = self.rect.collidelist(enemy_hit_list)
            if idx == -1:
                self.damage = 0   # تصفير قيمة المتغير
                self.health -= 1  # إنقاص نقطة من صحة اللاعب

لا تعمل التعليمات السابقة ما لم يحدث التصادم مع العدو فهي لا تتأثر بركض اللاعب في عالم اللعبة أو جمعه للجوائز والكنوز شرطها الوحيد هو تنشيط المتغير self.damage.

وعندما تعمل فإنها تستخدم Self.rect.collidelist لتبيان إن كان تصادم البطل مع عدو ينتمي لمجموعة الأعداء ما زال مستمرًا أم أنه انتهى (ويعطي عنها collidelist القيمة 1-) وبمجرد انتهاء التصادم تعاد قيمة المتغير self.damage وتخصم نقطة من صحة اللاعب.

شغل اللعبة الآن.

pygame-health

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

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

طور مهاراتك

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

سنضيف في المقال التالي بعض الآليات القتالية للعبة، وننهي هذا المقال بتذكيرك ببرنامج اللعبة كامًلا حتى الآن:

#!/usr/bin/env python3
# by Seth Kenlon

# GPLv3
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import pygame
import pygame.freetype
import sys
import os

'''
Variables
'''

worldx = 960
worldy = 720
fps = 40
ani = 4
world = pygame.display.set_mode([worldx, worldy])
forwardx  = 600
backwardx = 120

BLUE = (80, 80, 155)
BLACK = (23, 23, 23)
WHITE = (254, 254, 254)
ALPHA = (0, 255, 0)

tx = 64
ty = 64

font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "fonts", "amazdoom.ttf")
font_size = tx
pygame.freetype.init()
myfont = pygame.freetype.Font(font_path, font_size)


'''
Objects
'''

def stats(score,health):
    myfont.render_to(world, (4, 4), "Score:"+str(score), BLUE, None, size=64)
    myfont.render_to(world, (4, 72), "Health:"+str(health), BLUE, None, size=64)

# x location, y location, img width, img height, img file
class Platform(pygame.sprite.Sprite):
    def __init__(self, xloc, yloc, imgw, imgh, img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images', img)).convert()
        self.image.convert_alpha()
        self.image.set_colorkey(ALPHA)
        self.rect = self.image.get_rect()
        self.rect.y = yloc
        self.rect.x = xloc


class Player(pygame.sprite.Sprite):
    """
    Spawn a player
    """

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.movex = 0
        self.movey = 0
        self.frame = 0
        self.health = 10
        self.damage = 0
        self.score = 0
        self.is_jumping = True
        self.is_falling = True
        self.images = []
        for i in range(1, 5):
            img = pygame.image.load(os.path.join('images', 'hero' + str(i) + '.png')).convert()
            img.convert_alpha()
            img.set_colorkey(ALPHA)
            self.images.append(img)
            self.image = self.images[0]
            self.rect = self.image.get_rect()

    def gravity(self):
        if self.is_jumping:
            self.movey += 3.2

    def control(self, x, y):
        """
        control player movement
        """
        self.movex += x

    def jump(self):
        if self.is_jumping is False:
            self.is_falling = False
            self.is_jumping = True

    def update(self):
        """
        Update sprite position
        """

        # moving left
        if self.movex < 0:
            self.is_jumping = True
            self.frame += 1
            if self.frame > 3 * ani:
                self.frame = 0
            self.image = pygame.transform.flip(self.images[self.frame // ani], True, False)

        # moving right
        if self.movex > 0:
            self.is_jumping = True
            self.frame += 1
            if self.frame > 3 * ani:
                self.frame = 0
            self.image = self.images[self.frame // ani]

        # collisions
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
        if self.damage == 0:
            for enemy in enemy_hit_list:
                if not self.rect.contains(enemy):
                    self.damage = self.rect.colliderect(enemy)
        if self.damage == 1:
            idx = self.rect.collidelist(enemy_hit_list)
            if idx == -1:
                self.damage = 0   # set damage back to 0
                self.health -= 1  # subtract 1 hp

        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.movey = 0
            self.rect.bottom = g.rect.top
            self.is_jumping = False  # stop jumping

        # fall off the world
        if self.rect.y > worldy:
            self.health -=1
            print(self.health)
            self.rect.x = tx
            self.rect.y = ty

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.is_jumping = False  # stop jumping
            self.movey = 0
            if self.rect.bottom <= p.rect.bottom:
               self.rect.bottom = p.rect.top
            else:
               self.movey += 3.2

        if self.is_jumping and self.is_falling is False:
            self.is_falling = True
            self.movey -= 33  # how high to jump

        loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
        for loot in loot_hit_list:
            loot_list.remove(loot)
            self.score += 1
            print(self.score)

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)

        self.rect.x += self.movex
        self.rect.y += self.movey

class Enemy(pygame.sprite.Sprite):
    """
    Spawn an enemy
    """

    def __init__(self, x, y, img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images', img))
        self.image.convert_alpha()
        self.image.set_colorkey(ALPHA)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.counter = 0

    def move(self):
        """
        enemy movement
        """
        distance = 80
        speed = 8

        if self.counter >= 0 and self.counter <= distance:
            self.rect.x += speed
        elif self.counter >= distance and self.counter <= distance * 2:
            self.rect.x -= speed
        else:
            self.counter = 0

        self.counter += 1


class Level:
    def ground(lvl, gloc, tx, ty):
        ground_list = pygame.sprite.Group()
        i = 0
        if lvl == 1:
            while i < len(gloc):
                ground = Platform(gloc[i], worldy - ty, tx, ty, 'tile-ground.png')
                ground_list.add(ground)
                i = i + 1

        if lvl == 2:
            print("Level " + str(lvl))

        return ground_list

    def bad(lvl, eloc):
        if lvl == 1:
            enemy = Enemy(eloc[0], eloc[1], 'enemy.png')
            enemy_list = pygame.sprite.Group()
            enemy_list.add(enemy)
        if lvl == 2:
            print("Level " + str(lvl))

        return enemy_list

    # x location, y location, img width, img height, img file
    def platform(lvl, tx, ty):
        plat_list = pygame.sprite.Group()
        ploc = []
        i = 0
        if lvl == 1:
            ploc.append((200, worldy - ty - 128, 3))
            ploc.append((300, worldy - ty - 256, 3))
            ploc.append((550, worldy - ty - 128, 4))
            while i < len(ploc):
                j = 0
                while j <= ploc[i][2]:
                    plat = Platform((ploc[i][0] + (j * tx)), ploc[i][1], tx, ty, 'tile.png')
                    plat_list.add(plat)
                    j = j + 1
                print('run' + str(i) + str(ploc[i]))
                i = i + 1

        if lvl == 2:
            print("Level " + str(lvl))

        return plat_list

    def loot(lvl):
        if lvl == 1:
            loot_list = pygame.sprite.Group()
            loot = Platform(tx*5, ty*5, tx, ty, 'loot_1.png')
            loot_list.add(loot)

        if lvl == 2:
            print(lvl)

        return loot_list


'''
Setup
'''

backdrop = pygame.image.load(os.path.join('images', 'stage.png'))
clock = pygame.time.Clock()
pygame.init()
backdropbox = world.get_rect()
main = True

player = Player()  # spawn player
player.rect.x = 0  # go to x
player.rect.y = 30  # go to y
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10

eloc = []
eloc = [300, worldy-ty-80]
enemy_list = Level.bad(1, eloc)
gloc = []

i = 0
while i <= (worldx / tx) + tx:
    gloc.append(i * tx)
    i = i + 1

ground_list = Level.ground(1, gloc, tx, ty)
plat_list = Level.platform(1, tx, ty)
enemy_list = Level.bad( 1, eloc )
loot_list = Level.loot(1)


'''
Main Loop
'''

while main:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            try:
                sys.exit()
            finally:
                main = False

        if event.type == pygame.KEYDOWN:
            if event.key == ord('q'):
                pygame.quit()
                try:
                    sys.exit()
                finally:
                    main = False
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(-steps, 0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(steps, 0)
            if event.key == pygame.K_UP or event.key == ord('w'):
                player.jump()

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(steps, 0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(-steps, 0)

    # scroll the world forward
    if player.rect.x >= forwardx:
        scroll = player.rect.x - forwardx
        player.rect.x = forwardx
        for p in plat_list:
            p.rect.x -= scroll
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll

    # scroll the world backward
    if player.rect.x <= backwardx:
        scroll = backwardx - player.rect.x
        player.rect.x = backwardx
        for p in plat_list:
            p.rect.x += scroll
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll

    world.blit(backdrop, backdropbox)
    player.update()
    player.gravity()
    player_list.draw(world)
    enemy_list.draw(world)
    loot_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    for e in enemy_list:
        e.move()
    stats(player.score, player.health)
    pygame.display.flip()
    clock.tick(fps)

ترجمة -وبتصرف- للمقال Add scorekeeping to your Python game لصاحبيه Seth Kenlon و Jess Weichler.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...