خرید بک لینک

فریم‌ورک «کیوی» (kivy) یکی از بهترین ابزار‌ها برای ساخت بازی با پایتون برای اندروید است. فرض کنید که تصمیم گرفته‌ایم بازی برای اجرا شدن بر روی صفحات لمسی موبایل با سیستم عامل اندروید بنویسیم. مراحل کار به این صورت هستند که ابتدا باید سناریویی برای بازی بنویسیم. سپس بازی خود را طراحی می‌کنیم. بعد از ساخت بازی در مراحل آخر باید فایلی با پسوند APK یا AAB برای نصب این بازی بر روی سیستم عامل اندروید بسازیم. در پایان هم لازم است بتوانیم بازی ساخته شده را بر روی گوگل پلی یا نرم‌افزارهای مشابه بارگذاری کرده و برای دانلود در اختیار عموم مردم قرار دهیم. بازی‌سازی با پایتون یکی از پرطرفدارترین کاربرد‌های این زبان برنامه نویسی است.

در این گزارش از مجله فرادرس می‌آموزیم که چگونه با استفاده از کتابخانه «کیوی» (Kivy)، بازی «پینگ پونگ» (Pong) را بنویسیم. ابتدا کار خود را با نوشتن برنامه پایه شروع می‌کنیم و قدم‌به‌قدم آن را به یک بازی پونگ قابل اجرا تبدیل خواهیم کرد. در این مسیر تمامی مراحل را به طور کامل شرح می‌دهیم. در پایان هم بعد از توضیح دادن درباره روش ساخت فایل APK و AAB مراحل مربوط به انتشار این بازی بر روی گوگل پلی را بیان می‌کنیم.

پیش از شروع به کار باید ابزارهای مورد نیاز خود را تهیه کرده و بر روی سیستم نصب کنیم. در فهرست پایین به شکل خلاصه مهم‌ترین ابزارهای مورد نیاز برای ساخت بازی با پایتون برای اندروید را نوشته‌ایم.

در ادامه، تمام موارد بالا را یک به یک معرفی می‌کنیم و روش نصب آن‌ها را توضیح می‌دهیم.

«پایتون» (Python) زبان برنامه‌نویسی مفسری، سطح بالا و چندمنظوره است. بخش اصلی این بازی به زبان پایتون نوشته خواهد شد. زیرا این زبان برای افراد تازه‌کار بسیار مناسب است، ساختاری خلاصه دارد و یادگیری آن آسان است.

برای نصب این زبان برنامه نویسی کافیست که به وب‌سایت رسمی آن مراجعه کرده و جدید‌ترین نسخه همساز با سیستم عامل خود را انتخاب کرده و دانلود کنید.

لینک دسترسی به وب‌سایت رسمی پایتون (+)

«کیوی» (Kivy) کتابخانه‌ای رایگان و اوپن سورس در پایتون است که برای توسعه اپلیکیشن‌های موبایل و سایر نرم‌افزارهای «چندلمسی» (Multi-touch) با رابط کاربری طبیعی استفاده می‌شود. به زبان ساده‌تر، کیوی فریم‌ورکی است که به پایتون کمک می‌کند تا از دستگاه‌های چندلمسی مانند گوشی‌های هوشمند و تبلت‌ها پشتیبانی کند.

برای نصب کیوی دستور زیر را در خط فرمان نوشته و اجرا کنید.

«KivyMD» این ابزار، مجموعه‌ای از ویجت‌های سازگار با «متریال دیزاین» (Material Design) است که برای استفاده در کنار کتابخانه کیوی طراحی شده‌اند.

برای نصب KivyMD باید دستور زیر را در خط فرمان نوشته و این کتابخانه را نصب کنیم.

«بیلدوزر» (Buildozer) ابزاری است که با هدف بسته‌بندی و گرفتن آسان خروجی برای اپلیکیشن‌های موبایل مورد استفاده قرار می‌گیرد.

Buildozer به صورت مستقیم روی ویندوز اجرا نمی‌شود، اما کاربران ویندوز ۱۰ و ۱۱ می‌توانند با استفاده از «Windows Subsystem for Linux | WSL» محیط لینوکس را داخل ویندوز اجرا کرده و فایل APK اندروید بسازند.

در این گزارش، پروژه خود را بر روی ویندوز توسعه می‌دهیم. اما در بخش آخر و برای ساخت فایل APK از ترفندی ساده و بدون نیاز به نصب لینوکس بهره خواهیم برد. یعنی از کد ادیتور «GitHub Codespaces» کمک می‌گیریم.

تا به اینجای مطلب با مفاهیم و نیازمندی‌های اصلی در زمان ساخت بازی با پایتون برای اندروید آشنا شده‌اید. در ادامه اول بازی ساده‌ای به کمک فریم‌ورک کیوی برای اندروید می‌سازیم. سپس روش ساخت فایل APK و AAB و همین‌طور انتشار اپلیکیشن‌های اندرویدی در گوگل پلی را هم بررسی کرده‌ایم. در صورت تمایل به مطالعه مطالبی مانند این مورد، پیشنهاد می‌کنیم که اپلیکیشن مجله فرادرس را بر روی دستگاه‌های همراه خود نصب بکنید.

برای نصب اپلیکیشن رایگان مجله فرادرس، کلیک کنید.

بعد از نصب پیش‌نیازهای اجرای پروژه همه چیز برای ساخت بازی با پایتون برای اندروید، آماده شده است. در ابتدا اپلیکیشن ساده‌ای می‌سازیم تا با مفاهیم و اصول اولیه آشنا شویم.

در تصویر پایین ابزارهای مورد استفاده برای ساخت این پروژه را معرفی کرده‌ایم.

کار را با راه‌اندازی و اجرای برنامه‌ای بسیار ساده در کیوی آغاز می‌کنیم. ابتدا دایرکتوری برای بازی خود می‌سازیم و درون آن فایلی به نام «main.py» ایجاد می‌کنیم. کدهای زیر را در داخل این فایل می‌نویسیم.

from kivy.app import App
from kivy.uix.widget import Widget


class PongGame(Widget):
    pass


class PongApp(App):
    def build(self):
        return PongGame()


if __name__ == '__main__':
    PongApp().run()

برنامه را اجرا می‌کنیم. در این مرحله، بازی فقط پنجره‌ای سیاه نمایش می‌دهد. کاری که تا اینجا انجام داده‌ایم، ساخت برنامه‌ای بسیار ساده با کمک فریم‌ورک کیوی است. این برنامه «نمونه‌ای» (Instance) از كلاس ویجت [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] می‌سازد. سپس آن را به عنوان «عنصر اصلی» (Root Element) رابط کاربری اپلیکیشن بازمی‌گرداند.

برای درک بهتر این نوع پروژه‌ها باید ساختار برنامه‌های کیوی را به صورت «درخت سلسله‌مراتبی از ویجت‌ها» (Widgets Tree) تصور کنیم. خود کیوی این درخت را درون پنجره پیش‌فرض نمایش می‌دهد.

برای یادگیری ساخت بازی اندروید با پایتون یا حتی بازی‌های معمولی قابل اجرا بر روی دسکتاپ با پایتون باید صبور باشیم و مرحله‌به‌مرحله به پیش برویم. اولین مرحله شامل آشنایی با مفاهیم اولیه است. با رعایت مسیر درست می‌توانیم تا مراحل پیشرفته برنامه‌نویسی و کتابخانه‌های تخصصی این حوزه را هم یاد بگیریم و پروژه‌های قابل قبولی را اجرا کنیم. اما نکته مهم این است که برای ورود درست و پیشرفت در این حوزه لازم است از منابع آموزشی مناسب کمک بگیریم. انتخاب محتوای آموزشی صحیح به غیر از افزایش کیفیت یادگیری، سرعت آن را هم بیشتر می‌کند. بهترین مطالب متنی و فیلم‌های آموزشی را می‌توانید در وب‌سایت آموزشی فرادرس با تنوع زیاد پیدا کنید.

مطالعه و تماشای محتوای آموزشی فرادرس، به طور خاص فیلم‌های پروژه محور تاثیر بسیار زیادی در ارتقای مهارت‌های کاربران دارد. مجموعه آموزشی معرفی شده در بالا از فیلم‌هایی تشکیل شده‌ است که با هدف کمک به یادگیری تکنولوژی‌های مختلف در حوزهبازی‌سازی با پایتون طراحی شده‌اند. در فهرست پایین، چند مورد از فیلم‌های این مجموعه آموزشی را معرفی کرده‌ایم. برای تماشای فیلم‌های بیشتر می‌توانید بر روی عکس بالا کلیک کنید.

در بخش بعد، روش اضافه کردن تصاویر گرافیکی به بازی اندرویدی را بررسی کرده‌ایم.

در این بخش از مطلب می‌خواهیم چند مورد از اشکال گرافیکی ساده را طراحی کنیم. برای این کار باید فایلی با پسوند «kv.» بسازیم.

در این گزارش از فایلی با پسوند «kv.» برای تعریف ظاهر و محیط کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] استفاده می‌کنیم. از آنجا که نام کلاس اصلی برنامه [fdboutput]{"content":"PongApp%20","type":"inline"}[/fdboutput] است، به سادگی می‌توانیم فایلی به نام «pong.kv» در همان دایرکتوری بسازیم. این فایل در زمان اجرای برنامه، به صورت خودکار توسط کیوی بارگذاری می‌شود. بنابراین فایل جدیدی به نام pong.kv ایجاد کرده و محتوای کادر زیر را به آن اضافه کنید.

#:kivy 1.0.9

:
    canvas:
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height
            
    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: "0"
        
    Label:
        font_size: 70
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: "0"

نکته (خطای رایج): نام فایل Kv (در اینجا pong.kv است) باید دقیقا با نام کلاس اپلیکیشن (که در اینجا [fdboutput]{"content":"PongApp%20","type":"inline"}[/fdboutput] است) همخوانی داشته باشد. یعنی باید به طور دقیق از همان عبارتی استفاده کنیم که قبل از کلمه [fdboutput]{"content":"App%20","type":"inline"}[/fdboutput] در نام کلاس آمده است. بهتر است از حروف کوچک استفاده کنیم.

اگر اکنون برنامه را اجرا کنیم، باید یک خط عمودی در وسط صفحه و دو عدد صفر در محل نمایش امتیاز بازیکنان مشاهده کنیم.

پیش از رفتن به مرحله بعد، بهتر است نگاهی دقیق‌تر به محتوای فایل Kv کنیم و ببینیم در آن چه می‌گذرد. شاید با این ساختار آشنایی کامل داشته باشید. در این صورت، می‌توانید از این بخش عبور کرده و به مرحله بعدی بروید.

در اولین خط فایل، عبارت زیر نوشته شده است.

#:kivy 1.0.9

وجود این خط در ابتدای تمامی فایل‌های Kv الزامی است. این عبارت باید با [fdboutput]{"content":"%23%3Akivy","type":"inline"}[/fdboutput] شروع شده و پس از یک فاصله، نسخه کیوی مورد استفاده در جلوی آن نوشته شود. این کار به کیوی کمک می‌کند تا مطمئن شود سیستم حداقل نسخه مورد نیاز را دارد و در آینده بتواند با نسخه‌های قدیمی‌تر به راحتی سازگار شود.

پس از آن، قوانینی را تعریف کرده‌ایم که روی تمام نمونه‌های کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] اعمال می‌شوند.

:
    ...

فایل‌های Kv نیز مانند زبان پایتون، از دندانه‌گذاری (Indentation) برای تعریف بلوک‌های تو در تو استفاده می‌کنند. بلوکی که در آن نام هر کلاس درون علامت‌های [fdboutput]{"content":"%26lt%3B%20","type":"inline"}[/fdboutput] و [fdboutput]{"content":"%26gt%3B%20","type":"inline"}[/fdboutput] قرار می‌گیرد، «قانون ویجت» (Widget Rule) نام دارد. این قانون روی تمام نمونه‌های ساخته شده از کلاس مورد نظر اعمال خواهد شد. در این مثال، اگر به جای [fdboutput]{"content":"%26lt%3BPongGame%26gt%3B%20","type":"inline"}[/fdboutput] عبارت [fdboutput]{"content":"%26lt%3BWidget%26gt%3B%20","type":"inline"}[/fdboutput] را قرار می‌دادید، این خط عمودی و دو ویجت متنی به عنوان «برچسب» ([fdboutput]{"content":"Label","type":"inline"}[/fdboutput]) روی تمام نمونه‌های ساختار ویجت اعمال می‌شدند. زیرا قانون را برای کلاس پایه ویجت‌ها تعریف کرده‌ایم.

در هر «قانون» (Rule) می‌توانیم بخش‌های مختلفی را برای تعیین ظاهر و محتوای ویجت‌ها اضافه کنیم. برای مثال، می‌توانیم کارهای زیر را انجام دهیم.

اولین بلوکی که درون قانون[fdboutput]{"content":"%20%26lt%3BPongGame%26gt%3B%20","type":"inline"}[/fdboutput] داریم، بلوک [fdboutput]{"content":"canvas%20","type":"inline"}[/fdboutput] است.

:
    canvas:
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

این بلوک [fdboutput]{"content":"canvas%20","type":"inline"}[/fdboutput] مشخص می‌کند که ویجت [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] باید یک‌سری اشکال گرافیکی اولیه را ترسیم کند.

مزیت فوق‌العاده تعریف گرافیک به این شیوه آن است که با تغییر ویژگی‌های هر کدام از ویجت‌های به کار رفته در عبارت‌های مقداری، مستطیل رندر شده نیز به صورت خودکار بروزرسانی می‌شود.

نکته: سعی کنید اندازه پنجره برنامه را تغییر دهید و ببینید چه اتفاقی می‌افتد. باید وقتی پنجره برنامه را تغییر می‌دهید تمام رابط کاربری به طور خودکار تغییر سایز بدهد. رفتار استاندارد پنجره در کیوی به این صورت است که اندازه هر عنصر را بر اساس ویژگی [fdboutput]{"content":"size_hint%20","type":"inline"}[/fdboutput] آن تغییر می‌دهد.

مقدار پیش‌فرض [fdboutput]{"content":"size_hint","type":"inline"}[/fdboutput] برای هر ویجت [fdboutput]{"content":"(1%2C1)%20","type":"inline"}[/fdboutput] است. به این معنی که ۱۰۰٪ در جهت محور [fdboutput]{"content":"x%20","type":"inline"}[/fdboutput] و محور [fdboutput]{"content":"y%20","type":"inline"}[/fdboutput] کشیده می‌شود و در نتیجه فضای موجود را پر می‌کند. از آنجا که موقعیت و اندازه مستطیل و همچنین [fdboutput]{"content":"center_x%20","type":"inline"}[/fdboutput] و «لبه بالایی» ([fdboutput]{"content":"top","type":"inline"}[/fdboutput]) برچسب‌های امتیاز در چارچوب کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] تعریف شده‌اند، با تغییر ویژگی‌های ویجت والد آن‌ها، این مقادیر نیز به طور خودکار بروز خواهند شد. با استفاده از زبان اختصاصی فریم‌ورک Kv ویژگی «اتصال خودکار ویژگی‌ها» (Automatic Property Binding) به برنامه اضافه می‌شود.

دو بخش اضافه شده در آخر بسیار شبیه به هم هستند. هر کدام از آن‌ها ویجت [fdboutput]{"content":"Label","type":"inline"}[/fdboutput] یا برچسب متنی را به عنوان ویجت فرزند به ویجت اصلی [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] اضافه می‌کنند. در حال حاضر، متن هر دوی آن‌ها روی [fdboutput]{"content":"%220%22%20","type":"inline"}[/fdboutput] تنظیم شده است. پس از پیاده‌سازی منطق بازی، این متن‌ها را به امتیاز واقعی متصل می‌کنیم. اما این برچسب‌ها از همین حالا هم ظاهر خوبی دارند، چرا که «اندازه فونت» ([fdboutput]{"content":"font_size","type":"inline"}[/fdboutput] ) بزرگ‌تری برایشان در نظر گرفته‌ایم و موقعیت آن‌ها را به صورت وابسته به ویجت اصلی تنظیم کرده‌ایم.

از کلمه کلیدی [fdboutput]{"content":"root%20","type":"inline"}[/fdboutput] می‌توانیم درون بلوک فرزند برای ارجاع به ویجت «والد» یا «ریشه‌» یا همان ویجت اصلی استفاده کنیم. در نهایت، تمام قوانین بر روی همین ویجت اصلی اعمال می‌شوند. در اینجا [fdboutput]{"content":"PongGame","type":"inline"}[/fdboutput] ویجت اصلی یا والد است.

:
    # ...

    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: "0"

    Label:
        font_size: 70
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: "0"

افزودن توپ به بازی

خیلی خوب، اکنون زمین بازی ساده برای پینگ‌پونگ را ساخته‌ایم. اما بازیکن و توپی برای ضربه زدن نداریم. در ادامه مطلب، می‌خواهیم دو بازیکن و یک توپ پیاده‌سازی کنیم. کار خود را با توپ شروع می‌کنیم. ابتدا کلاس جدیدی به نام [fdboutput]{"content":"PongBall%20","type":"inline"}[/fdboutput] ایجاد می‌کنیم تا ویجتی بسازیم که نقش توپ را ایفا کند و در صفحه به حرکت و جهش در بیاید.

در ادامه، کدهای پایتون مربوط به کلاس [fdboutput]{"content":"PongBall%20","type":"inline"}[/fdboutput] آورده شده است:

class PongBall(Widget):

    # velocity of the ball on x and y axis
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)

    # referencelist property so we can use ball.velocity as
    # a shorthand, just like e.g. w.pos for w.x and w.y
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    # ``move`` function will move the ball one step. This
    # will be called in equal intervals to animate the ball
    def move(self):
        self.pos = Vector(*self.velocity) + self.pos

در کادر پایین، روش مورد استفاده در کیوی برای رسم کردن توپ به شکل دایره سفید را پیاده‌سازی کرده‌ایم.

:
    size: 50, 50
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size

برای کار کردن همه این کدها لازم است از بخش [fdboutput]{"content":"properties%20","type":"inline"}[/fdboutput] در کیوی ماژول‌های مربوط به ویژگی‌های مختلف مانند «[fdboutput]{"content":"NumericProperty","type":"inline"}[/fdboutput]» و «[fdboutput]{"content":"ReferenceListProperty","type":"inline"}[/fdboutput]» را نیز به محیط کدنویسی ایمپورت کنیم. در ضمن باید از بخش «[fdboutput]{"content":"vector","type":"inline"}[/fdboutput] » هم ماژول [fdboutput]{"content":"Vector","type":"inline"}[/fdboutput] را استفاده کنیم.

در کادر پایین، تمام به‌روزرسانی‌های مربوط به کدهای پایتون و فایل Kv مربوط به این مرحله را نوشته‌ایم. این کدها مربوط به فایل main.py هستند.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty
from kivy.vector import Vector


class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos


class PongGame(Widget):
    pass


class PongApp(App):
    def build(self):
        return PongGame()


if __name__ == '__main__':
    PongApp().run()

کدهای نوشته شده در پایین هم باید در فایل pong.kv نوشته شوند.

#:kivy 1.0.9

:
    size: 50, 50 
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size

:
    canvas:
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: "0"
        
    Label:
        font_size: 70
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: "0"

    PongBall:
        center: self.parent.center

نکته: توجه داشته باشید که نه تنها قانونی برای ویجت [fdboutput]{"content":"%26lt%3BPongBall%26gt%3B%20","type":"inline"}[/fdboutput] اضافه شده، بلکه ویجت فرزندی به نام [fdboutput]{"content":"PongBall%20","type":"inline"}[/fdboutput] نیز درون قانون ویجت [fdboutput]{"content":"%26lt%3BPongGame%26gt%3B%20","type":"inline"}[/fdboutput] قرار گرفته است.

بسیار عالی، اکنون توپی داریم که حتی تابعی هم برای حرکت به نام تابع [fdboutput]{"content":"move","type":"inline"}[/fdboutput] برای آن تعریف شده است. اما توپ بازی، هنوز حرکت نمی‌کند. بیایید این مشکل را نیز برطرف کنیم.

الان لازم است متد [fdboutput]{"content":"move%20","type":"inline"}[/fdboutput] مربوط به توپ، به صورت منظم و مداوم فراخوانی شود. خوشبختانه، کیوی این کار را بسیار آسان کرده است. به طوری که به برنامه نویس اجازه می‌دهد:

Clock.schedule_interval(game.update, 1.0/60.0)

برای مثال، این خط کد باعث می‌شود که تابع [fdboutput]{"content":"update%20","type":"inline"}[/fdboutput] از شی [fdboutput]{"content":"game","type":"inline"}[/fdboutput]، یک‌بار در هر یک‌شصتم ثانیه، یعنی ۶۰ بار در ثانیه، فراخوانی شود.

غیر از به حرکت درآوردن توپ با مشکل دیگری هم روبه‌رو هستیم. اکنون باید مطمئن شویم که تابع [fdboutput]{"content":"move%20","type":"inline"}[/fdboutput] از کلاس [fdboutput]{"content":"PongBall%20","type":"inline"}[/fdboutput] به صورت منظم فراخوانی می‌شود. اما در کدهای پایتون خود هیچ ارجاع یا دسترسی مستقیمی به شی توپ نداریم. چرا که آن را فقط از طریق فایل Kv و درون قانون مربوط به کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] اضافه کرده‌ایم. در حال حاضر، تنها ارجاعی که به بازی خود داریم، همان شیئی است که در متد [fdboutput]{"content":"build%20","type":"inline"}[/fdboutput] اپلیکیشن بازمی‌گردانیم.

توجه کنید که در آینده کارهای بیشتری به جز حرکت دادن ساده توپ داریم. برای مثال، موارد زیر، دو مورد از حرکات مهم این بازی هستند.

در هر صورت به متد [fdboutput]{"content":"update%20","type":"inline"}[/fdboutput] برای کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] نیاز خواهیم داشت. علاوه بر این، با توجه به اینکه از قبل به شی [fdboutput]{"content":"game","type":"inline"}[/fdboutput] دسترسی داریم، به راحتی می‌توانیم متد [fdboutput]{"content":"update%20","type":"inline"}[/fdboutput] جدید آن را در زمان ساخته شدن برنامه یا همان اجرای متد [fdboutput]{"content":"build","type":"inline"}[/fdboutput] زمان‌بندی کنیم.

class PongGame(Widget):

    def update(self, dt):
        # call ball.move and other stuff
        pass

class PongApp(App):

    def build(self):
        game = PongGame()
        Clock.schedule_interval(game.update, 1.0/60.0)
        return game

با این حال، موضوع هنوز این واقعیت وجود دارد که در برنامه هیچ ارجاعی به ویجت فرزند [fdboutput]{"content":"PongBall","type":"inline"}[/fdboutput] نداریم. برای حل این مشکل، ویژگی [fdboutput]{"content":"ObjectProperty%20","type":"inline"}[/fdboutput] را به کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] اضافه کرده و آن را به ویجت ساخته شده در قانون Kv متصل می‌کنیم. به محض انجام شدن این کار، می‌توانیم به راحتی به ویژگی [fdboutput]{"content":"ball%20","type":"inline"}[/fdboutput] در متد [fdboutput]{"content":"update%20","type":"inline"}[/fdboutput] ارجاع دهیم و حتی کاری کنیم که توپ پس از برخورد با لبه‌های صفحه، به عقب جهش کند.

class PongGame(Widget):
    ball = ObjectProperty(None)

    def update(self, dt):
        self.ball.move()

        # bounce off top and bottom
        if (self.ball.y < 0) or (self.ball.top > self.height):
            self.ball.velocity_y *= -1

        # bounce off left and right
        if (self.ball.x < 0) or (self.ball.right > self.width):
            self.ball.velocity_x *= -1

فراموش نکنید که کدهای نوشته شده را باید به فایل Kv اضافه کنیم. با تخصیص شماره شناسایی یا همان [fdboutput]{"content":"id%20","type":"inline"}[/fdboutput] به ویجت فرزند می‌توانیم صفت [fdboutput]{"content":"ObjectProperty%20","type":"inline"}[/fdboutput] در شی توپ یا همان [fdboutput]{"content":"ball%20","type":"inline"}[/fdboutput] را به شماره شناسایی مورد نظر متصل کنیم.

:
    ball: pong_ball

    # ... (canvas and Labels)

    PongBall:
        id: pong_ball
        center: self.parent.center

نکته: در این مرحله، همه چیز برای جهش و حرکت توپ به این سو و آن سو آماده شده است. اگر در حین مطالعه آموزش، خودتان هم قدم‌به‌قدم کدها را می‌نویسید، شاید برایتان سوال شده باشد که چرا توپ هیچ حرکتی نمی‌کند. علت این است که سرعت ([fdboutput]{"content":"Velocity","type":"inline"}[/fdboutput]) توپ در هر دو جهت [fdboutput]{"content":"x%20","type":"inline"}[/fdboutput] و [fdboutput]{"content":"y%20","type":"inline"}[/fdboutput] روی [fdboutput]{"content":"0","type":"inline"}[/fdboutput] تنظیم شده است.

در قطعه کد زیر، متدی به نام [fdboutput]{"content":"serve_ball%20","type":"inline"}[/fdboutput] به کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] اضافه شده و در متد [fdboutput]{"content":"build%20","type":"inline"}[/fdboutput] برنامه فراخوانی شده است. این متد، مقداری به عنوان سرعت تصادفی در جهت [fdboutput]{"content":"x%20","type":"inline"}[/fdboutput] و [fdboutput]{"content":"y%20","type":"inline"}[/fdboutput] به توپ اختصاص می‌دهد و همچنین موقعیت آن را ریست می‌کند. بنابراین می‌توانیم بعدا و پس از کسب امتیاز توسط بازیکنان، از این متد برای شروع مجدد حرکت توپ استفاده کنیم.

در ادامه، کد کامل این مرحله آورده شده است. این کدها را باید در فایل main.py بنویسیم.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import (
    NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint


class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos


class PongGame(Widget):
    ball = ObjectProperty(None)

    def serve_ball(self):
        self.ball.center = self.center
        self.ball.velocity = Vector(4, 0).rotate(randint(0, 360))

    def update(self, dt):
        self.ball.move()

        # bounce off top and bottom
        if (self.ball.y < 0) or (self.ball.top > self.height):
            self.ball.velocity_y *= -1

        # bounce off left and right
        if (self.ball.x < 0) or (self.ball.right > self.width):
            self.ball.velocity_x *= -1


class PongApp(App):
    def build(self):
        game = PongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return game


if __name__ == '__main__':
    PongApp().run()

کدهای زیر هم مربوط به فایل pong.kv هستند.

#:kivy 1.0.9

:
    size: 50, 50 
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size

:
    ball: pong_ball
    
    canvas:
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: "0"

    Label:
        font_size: 70
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: "0"

    PongBall:
        id: pong_ball
        center: self.parent.center

متصل کردن رویدادهای ورودی

یکی دیگر از کارهای باقی‌مانده در این بازی، تعریف بازیکنان و مدیریت رویداد‌های مربوط به ورودی‌های لمسی است. اکنون توپ در صفحه حرکت می‌کند و می‌جهد. تنها چیزهایی که کم داریم، راکت‌های متحرک بازیکنان و ثبت امتیازها است.

تمام این تکنیک‌ها در این گزارش به شکل کامل آموزش داده می‌شوند. اما اگر به استفاده از فیلم‌‌های آموزشی بیشتر علاقه دارید یا می‌خواهید مثال‌های بیشتری ببینید، پیشنهاد می‌کنیم فیلم آموزش برنامه نویسی اندروید در پایتون با فریم ورک کیوی Kivy + گواهینامه را در فرادرس مشاهده کنید. به منظور کمک به مخاطبان مجله، لینک دسترسی به این فیلم را در پایین نیز قرار داده‌ایم.

در این بخش دیگر به جزئیات ساخت کلاس و قوانین فایل Kv نخواهیم پرداخت، چرا که این مفاهیم را در مراحل قبلی بررسی کردیم. در عوض، روی این موضوع تمرکز می‌کنیم که چگونه ویجت‌های «بازیکن» ([fdboutput]{"content":"Player","type":"inline"}[/fdboutput]) را در پاسخ به ورودی‌های کاربر حرکت دهیم. کد کامل پایتون و قوانین Kv مربوط به کلاس [fdboutput]{"content":"PongPaddle%20","type":"inline"}[/fdboutput] را در پایان این بخش، قرار داده‌ایم.

در کتابخانه کیوی، هر ویجت با پیاده‌سازی متدهای زیر می‌تواند به ورودی‌های کاربر واکنش نشان دهد.

کلاس پایه Widget به صورت پیش‌فرض این متدها را برای همه ویجت‌های فرزند خود فراخوانی می‌کند. به این ترتیب، رویداد به همه آن‌ها ارسال می‌شود. این فرایند تا زمانی ادامه پیدا می‌کند که یکی از ویجت‌های فرزند مقدار [fdboutput]{"content":"True%20","type":"inline"}[/fdboutput] را برگرداند.

بازی پونگ منطق ساده‌ای دارد. راکت‌ها فقط باید به سمت بالا و پایین حرکت کنند. به همین دلیل، لازم نیست خود ویجت‌های بازیکن این رویدادها را مدیریت کنند. کافی است متد [fdboutput]{"content":"on_touch_move","type":"inline"}[/fdboutput] را در کلاس [fdboutput]{"content":"PongGame","type":"inline"}[/fdboutput] پیاده‌سازی کنیم. سپس موقعیت راکت سمت چپ یا راست را بر اساس محل لمس صفحه تغییر دهیم. اگر کاربر سمت چپ صفحه را لمس کند، راکت سمت چپ حرکت می‌کند. اگر سمت راست صفحه را لمس کند، راکت سمت راست جابه‌جا می‌شود.

در کادر زیر، تابع مدیریت‌کننده [fdboutput]{"content":"on_touch_move%20","type":"inline"}[/fdboutput] را پیاده‌سازی کرده‌ایم.

def on_touch_move(self, touch):
    if touch.x < self.width/3:
        self.player1.center_y = touch.y
    if touch.x > self.width - self.width/3:
        self.player2.center_y = touch.y

امتیاز هر بازیکن را در ویژگی [fdboutput]{"content":"NumericProperty%20","type":"inline"}[/fdboutput] مربوط به همان بازیکن ذخیره می‌کنیم. هر زمان مقدار این ویژگی تغییر کند، برچسب نمایش امتیاز در کلاس [fdboutput]{"content":"PongGame%20","type":"inline"}[/fdboutput] نیز به صورت خودکار به‌روزرسانی می‌شود. دلیل این موضوع آن است که ویژگی‌های کیوی به طور خودکار با ارجاع‌های موجود در فایل‌های Kv مرتبط می‌شوند.

علاوه بر این، کلاس [fdboutput]{"content":"PongPaddle%20","type":"inline"}[/fdboutput] متدی به نام [fdboutput]{"content":"bounce_ball%20","type":"inline"}[/fdboutput] دارد. این متد، مشخص می‌کند توپ پس از برخورد با راکت چگونه حرکت کند. زاویه و سرعت توپ نیز به محل برخورد آن با راکت بستگی دارد.

در ادامه، کدهای مربوط به کلاس [fdboutput]{"content":"PongPaddle%20","type":"inline"}[/fdboutput] آورده شده است.

class PongPaddle(Widget):

    score = NumericProperty(0)

    def bounce_ball(self, ball):
        if self.collide_widget(ball):
            speedup  = 1.1
            offset = 0.02 * Vector(0, ball.center_y-self.center_y)
            ball.velocity =  speedup * (offset - ball.velocity)

نکته: الگوریتم نوشته شده برای جهش توپ، بسیار ساده است. اما اگر توپ از پهلو یا از سمت پایین به راکت برخورد کند، رفتار عجیبی از خود نشان خواهد داد. این مسئله را تست کنید و در صورت تمایل به عنوان یکی از چالش‌های برنامه نویسی بازی، خودتان آن را مدیریت کنید.

در کادر پایین، این متد را در ساختار اصلی برنامه مشاهده می‌کنید. پروژه ساخت بازی با پایتون برای اندروید با پیاده‌سازی بازی پینگ‌پونگ در فایل main.py تقریبا تمام شده است.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import (
    NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
from kivy.clock import Clock


class PongPaddle(Widget):
    score = NumericProperty(0)

    def bounce_ball(self, ball):
        if self.collide_widget(ball):
            vx, vy = ball.velocity
            offset = (ball.center_y - self.center_y) / (self.height / 2)
            bounced = Vector(-1 * vx, vy)
            vel = bounced * 1.1
            ball.velocity = vel.x, vel.y + offset


class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos


class PongGame(Widget):
    ball = ObjectProperty(None)
    player1 = ObjectProperty(None)
    player2 = ObjectProperty(None)

    def serve_ball(self, vel=(4, 0)):
        self.ball.center = self.center
        self.ball.velocity = vel

    def update(self, dt):
        self.ball.move()

        # bounce off paddles
        self.player1.bounce_ball(self.ball)
        self.player2.bounce_ball(self.ball)

        # bounce ball off bottom or top
        if (self.ball.y < self.y) or (self.ball.top > self.top):
            self.ball.velocity_y *= -1

        # went off to a side to score point?
        if self.ball.x < self.x:
            self.player2.score += 1
            self.serve_ball(vel=(4, 0))
        if self.ball.right > self.width:
            self.player1.score += 1
            self.serve_ball(vel=(-4, 0))

    def on_touch_move(self, touch):
        if touch.x < self.width / 3:
            self.player1.center_y = touch.y
        if touch.x > self.width - self.width / 3:
            self.player2.center_y = touch.y


class PongApp(App):
    def build(self):
        game = PongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return game


if __name__ == '__main__':
    PongApp().run()

البته بخش مهم پروژه ساخت بازی با پایتون برای اندروید در فایل pong.kv نوشته شده است. در کادر پایین، نسخه کامل فایل pong.kv را نیز مشاهده می‌کنید.

#:kivy 1.0.9

:
    size: 50, 50 
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size

:
    size: 25, 200
    canvas:
        Rectangle:
            pos: self.pos
            size: self.size

:
    ball: pong_ball
    player1: player_left
    player2: player_right

    canvas:
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 50
        text: str(root.player1.score)

    Label:
        font_size: 70
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: str(root.player2.score)

    PongBall:
        id: pong_ball
        center: self.parent.center

    PongPaddle:
        id: player_left
        x: root.x
        center_y: root.center_y

    PongPaddle:
        id: player_right
        x: root.width - self.width
        center_y: root.center_y

ساخت فایل APK از بازی

بعد از ساخت بازی با پایتون برای اندروید باید نسخه APK پروژه خود را هم ایجاد کنیم. برای رسیدن به این هدف سه ابزار مختلف و پرکاربرد وجود دارد.

به کاربران تازه‌کار توصیه می‌کنیم که از بیلدوزر استفاده کنند. چون که این ابزار راحت‌ترین روش را برای ساخت فایل کامل APK یا AAB ارائه داده است. علاوه بر این، همان‌طور که در بالا اشاره کردیم، با اپلیکیشن Kivy Launcher نیز می‌توانید برنامه کیوی خود را بدون نیاز به طی کردن مرحله کامپایل، مستقیما روی گوشی اجرا کنید.

اپلیکیشن‌های ساخته شده با کیوی را می‌توان در مارکت‌های اندرویدی مانند گوگل «پلی استور» (Play Store) نیز منتشر کرد. البته این کار نیازمند طی کردن چند مرحله اضافه برای ساخت فایل «AAB» یا (Android App Bundle) است. که در بخش‌های بعد توضیح خواهیم داد.

«بیلدوزر» (Buildozer) ابزاری است که اجرای کل فرآیند بیلد و خروجی گرفتن را به صورت خودکار انجام می‌دهد. این ابزار تمام پیش‌نیازهای مربوط به پروژه Python-For-Android از جمله Android SDK و NDK را دانلود و تنظیم می‌کند. سپس فایل APK می‌سازد که می‌توان آن را به صورت خودکار به دستگاه اندرویدی منتقل کرد.

در حال حاضر، بیلدوزر تنها روی سیستم‌عامل‌های لینوکس و macOS کار می‌کند. البته همچنان می‌توانید در ویندوز از طریق WSL از آن استفاده کنید. استفاده از این ابزار فرآیند ساخت فایل APK را به شدت ساده‌تر می‌کند.

راحت‌ترین روش برای استفاده از Buildozer، برای کاربران ویندوز کمک گرفتن از گیت‌هاب است. به این منظور باید مراحل زیر را طی کنید.

بیلدوزر گزینه‌ها و ابزارهای متنوع زیادی را برای کمک به برنامه نویسان در نظر گرفته است. مراحلی نوشته شده در بالا فقط ساده‌ترین راه برای ساخت و اجرای فایل APK بودند.

برنامه نویسان می‌توانند کار بسته‌بندی برنامه را به شکل مستقیم با خود پروژه Python-For-Android هم انجام بدهند. در واقع Buildozer خود از Python-for-Android برای کامپایل برنامه‌های اندرویدی استفاده می‌کند. با این تفاوت که Buildozer بسیاری از مراحل را به صورت خودکار انجام می‌دهد. اما در این روش کنترل و مدیریت بیشتری روی فرآیند کار به برنامه نویس داده می‌شود. برنامه نویس برای استفاده از این روش باید بخش‌هایی از «ابزارهای اندروید» (Android Toolchain) را به صورت دستی دانلود و تنظیم کند.

در فهرست زیر مراحل انجام این کار در Codespace گیت‌هاب به صورت خلاصه بیان شده‌اند.

اگر هدف فقط ساخت فایل APK برای پروژه بازی پونگ باشد، استفاده از Buildozer انتخاب ساده‌تر و مناسب‌تری است. زیرا این ابزار، بسیاری از مراحل نصب و پیکربندی را به صورت خودکار انجام می‌دهد. اما اگر به تنظیمات پیشرفته‌تر یا کنترل بیشتر روی فرایند ساخت نیاز دارید، استفاده مستقیم از Python-for-Android گزینه انعطاف‌پذیرتری است.

برنامه Kivy Launcher اپلیکیشن اندرویدی است که می‌تواند هر نوع نمونه کد یا برنامه کیوی ذخیره شده روی کارت حافظه را به راحتی اجرا کند. یعنی سیستم‌های اندرویدی بدون نیاز به تبدیل فایل‌ها به APK می‌توانند آن‌‌ها را اجرا کنند.

برای نصب Kivy Launcher باید مراحل زیر را انجام دهید.

در کادر بالا عبارت [fdboutput]{"content":"%26lt%3Byourapplication%26gt%3B","type":"inline"}[/fdboutput] دایرکتوری را نشان می‌دهد که شامل فایل‌های main.py و «android.txt» است. فایل‌ main.py به عنوان اپلیکیشن اصلی به کار برده می‌شود. فایل android.txt نیز شامل اطلاعاتی درباره نیازمندی‌های کیوی برای اجرای اپلیکیشن بر روی اندروید است.

محتوای فایل android.txt باید به شکل زیر باشد:

این گزینه‌ها صرفا تنظیمات بسیار اولیه و پایه هستند. اگر تصمیم بگیرید با استفاده از ابزارهای بالا فایل APK اختصاصی خودتان را بسازید، به تنظیمات بسیار متنوع دیگری نیز دسترسی خواهید داشت.

نکته: نصب Kivy Launcher کمی فنی و تخصصی است و این اپلیکیشن کاربردی زمان زیادی است که به‌روزرسانی نشده. بنابراین بهتر است از دو روش بالا به طور خاص Buildozer استفاده کنید.

فرادرس به منظور کمک به تمام افراد علاقه‌مند به برنامه نویسی اندروید، مجموعه‌ای از فیلم‌های آموزشی را تولید و منتشر کرده است. با مشاهده این فیلم‌ها روش ساخت انواع اپلیکیشن برای دستگاه‌های اندرویدی را یاد می‌گیرید. مهم‌ترین ویژگی‌ دستگاه‌های اندرویدی وجود صفحه لمسی در آن‌ها است. برای همین باید از ابزارهای خاصی هم برای برنامه نویسی کمک بگیریم. «سیستم‌عامل» (Operating System | OS) اندروید توسط گوگل برای گوشی‌های موبایل و سایر دستگاه‌ها توسعه یافته است. با یاد گرفتن برنامه نویسی اندروید می‌توانیم موقعیت‌های شغلی جذابی بدست بیاوریم.

در پایین چند مورد از فیلم‌های آموزشی فرادرس درباره آموزش برنامه نویسی اندروید را معرفی کرده‌ایم.

برای مشاهده فیلم‌های بیشتر بر روی تصویر زیر کلیک کرده و به صفحه اصلی این مجموعه آموزشی هدایت شوید.

تا اینجا با استفاده از Buildozer یا Python-for-Android فایل‌های APK و AAB برنامه را ایجاد کرده‌ایم. اکنون می‌خواهیم نسخه نهایی آن را برای انتشار در Google Play آماده کنیم.

نکته: طبق مستندات Google Play، برنامه‌های جدید باید به صورت «Android App Bundle | AAB» منتشر شوند. سپس Google Play متناسب با دستگاه هر کاربر، فایل APK مناسب را تولید و در اختیار او قرار می‌دهد.

قبل از انتشار اپلیکیشن باید نسخه «Release» آن را بسازیم. اگر از Buildozer استفاده می‌کنید، کافی است دستور زیر را اجرا کنید.

در صورت استفاده از Python-for-Android نیز باید عبارت [fdboutput]{"content":"--release%20","type":"inline"}[/fdboutput] را به دستور ساخت برنامه اضافه کنید. پس از پایان عملیات، فایل خروجی برنامه در پوشه bin پروژه قرار می‌گیرد. Google Play برای انتشار برنامه‌های جدید از قالب AAB استفاده می‌کند.

قبل از انتشار برنامه باید آن را با «کلید دیجیتال» (Keystore) امضا کنید. اگر تاکنون Keystore نساخته‌اید با ابزار keytool موجود در JDK می‌توانید آن را ایجاد کنید. اگر در بخش قبل از «GitHub Codespaces» برای ساخت فایل AAB استفاده کرده‌اید، همین Codespace را باز نگه دارید و دستور زیر را در پنجره Terminal آن اجرا کنید.

پس از اجرای دستور، برنامه چند سوال مانند کلمه عبور Keystore، نام، سازمان و کشور را می‌پرسد. پس از پاسخ دادن به این پرسش‌ها، فایل «my-release-key.jks» در پوشه جاری پروژه ایجاد می‌شود. این فایل را در محل امنی نگهداری کنید، زیرا برای انتشار نسخه‌های بعدی برنامه نیز به همین کلید نیاز خواهید داشت.

اگر از Buildozer استفاده می‌کنید، کافی است مشخصات Keystore را در فایل buildozer.spec وارد کنید تا هنگام اجرای دستور [fdboutput]{"content":"buildozer%20android%20release%20","type":"inline"}[/fdboutput] فایل خروجی به صورت خودکار امضا شود.

ایجاد برنامه در Google Play Console دو بخش اصلی دارد.

پس از تکمیل اطلاعات برنامه، وارد بخش Production شوید. مهم‌ترین مراحل کار این قسمت را در پایین نوشته‌ایم.

در این گزارش از مجله فرادرس، مراحل ساخت بازی با پایتون برای اندروید را با استفاده از فریم‌ورک Kivy به صورت گام‌به‌گام یاد گرفتیم. ابتدا ابزارهای مورد نیاز مانند پایتون، Kivy و KivyMD و Buildozer را معرفی کردیم. سپس ساختار اولیه پروژه را ایجاد کرده و رابط کاربری را با فایل‌های KV طراحی کردیم. در ادامه، بخش‌های اصلی بازی مانند توپ و راکت را به پروژه اضافه کردیم. همچنین نحوه مدیریت رویدادهای لمسی، پیاده‌سازی حرکت بازیکنان و ثبت امتیاز را نیز بررسی کردیم.

در ادامه، با روش‌های ساخت فایل‌های APK و AAB آشنا شدیم. همچنین نحوه استفاده از ابزارهایی مانند Buildozer و Python-for-Android را یاد گرفتیم و برنامه را روی دستگاه‌های اندرویدی اجرا کردیم. علاوه بر این، روش انتشار بازی در گوگل پلی استور و نحوه استفاده از قابلیت‌های اختصاصی سیستم‌عامل اندروید را نیز بررسی کردیم. این آموزش، تمام مراحل ساخت بازی با پایتون برای اندروید را از طراحی اولیه تا ساخت فایل خروجی و انتشار برنامه پوشش می‌دهد. به همین دلیل، می‌تواند راهنمای مناسبی برای علاقه‌مندان به بازی‌سازی با پایتون باشد.

نوشته ساخت بازی با پایتون برای اندروید – به زبان ساده + خروجی APK اولین بار در فرادرس - مجله‌. پدیدار شد.



سوالات متداول

مهم‌ترین نکات درباره برنامه چیست؟

جزئیات مهم و نکات قابل توجه درباره برنامه در متن مقاله بررسی شده است.

آخرین اطلاعات درباره بازی چیست؟

جدیدترین اطلاعات و تغییرات مربوط به بازی در این گزارش ارائه شده است.

ساخت بازی با پایتون برای اندروید – به زبان ساده + خروجی APK چیست؟

در این مطلب اطلاعات، جزئیات و نکات مرتبط با ساخت بازی با پایتون برای اندروید – به زبان ساده + خروجی APK بررسی شده است.

برچسب: نویسنده: خنجی تاريخ: پنجشنبه 8 مرداد 1405 ساعت: 10:49

صفحه بندی

خبرنامه