ساخت بازی در اندروید قسمت دوم

1395/1/12 هومن حیدری 7168

احتمالا اگه الان ازتون بپرسم تعریفتون از واژه "جاوا" چیه، حدود 80 الی 90 درصدتون با قاطعیت میگید که جاوا یک زبان برنامه نویسیه!

آمار خیره کننده ایه! باور کنید من نمیتونم در مقابل این سطح از قاطعیت شما بایستم! چون دارید صحیح میفرمایید، بله جاوا یک زبان برنامه نویسیه! اما جاوا "تنها" یک زبان برنامه نویسیه؟!

البته اگه ذره ای جاوا-دان باشید حتما با این مفاهیم و ماهیت دوگانه جاوا آشنایید، ولی چه بهتر اگه یه کم جدی تر بهش بپردازیم!

بسیار خب؛ ببینید دوستان، جاوا علاوه بر اینکه یک زبان برنامه نویسیه، یک پلتفرم هم هست. جالبه! خب تعریفمون از پلتفرم چی باشه؟! معمولا از اصطلاح پلتفرم تو جاهای مختلف استفاده های متفاوتی میشه! به عنوان مثال این واژه میتونه به نوع (معماری) پردازنده/نوع سخت افزاری که یک سیستم عامل یا یک برنامه قراره روش اجرا شه اشاره کنه، یا میتونه تنها به نوع سیستم عامل بر روی یک کامپیوتر اشاره داشته باشه. البته بیشتر پلتفرم ها (مثل ویندوز، لینوکس، سولاریس و مک) میتونن به عنوان ترکیبی از سیستم عامل و سخت افزار زیرینش توصیف شن که بهشون پلتفرم های مبتنی بر سخت افزار هم میگن! اما به طور کلی برامون مهم نیست! چون پلتفرم جاوا یک استثناس و تو هیچ کدوم از این دسته ها جای نمیگیره! پلتفرم جاوا یک پلتفرم فقط-نرم افزاریه که روی پلتفرم های مبتنی بر سخت افزار دیگه اجرا میشه.

خب برگردیم سر جای اولمون؛ داشتیم میگفتیم که تکنولوژی جاوا هم اشاره داره به یک زبان برنامه نویسی و هم یک پلتفرم! شرکت اوراکل (همه کاره ی جاوا هستن ایشون!) این پلتفرم رو ایجاد کرده به 2 دلیل:

1. برنامه های جاوا تنها قابلیت اجرا شدن بر روی این پلتفرم رو داشته باشن! (چرا؟ عرض میکنم!)

2. توسعه جاوارو براتون سهل و آسون کنه! (چگونه؟ عرض میکنم!) (چرا؟ چون "باید کار کردن باهاش آسون باشه" یکی از اصلی ترین اهداف ایجاد زبان جاوا بود!)

راستی این پلتفرمه کو؟ کجاست؟!

شما وقتی JRE نصب میکنید رو سیستمتون (چون JDK نصب کردید JRE هم باهاش نصب شده!)، در واقع دارید پلتفرم جاوارو روی سیستم خودتون پیاده سازی میکنید. البته JRE به تنهایی امکان توسعه جاوارو براتون فراهم نمیکنه (فقط عرض کردم که آسون ترش میکنه!) و به همین دلیله که JDK نصب میکنید. JDK علاوه بر JRE شامل ابزار توسعه جاواست (مثل کامپایلر جاوا). اما برای اینکه همه چی بیشتر براتون روشن شه و منم بتونم پاسخگوی سوالات احتمالی تون باشم، باید بررسی کنیم که پلتفرم جاوا چه ساختاری داره!

پلتفرم جاوا تشکیل شده از یک ماشین مجازی (virtual machine) و یک محیط اجرایی (execution environment).

ماشین مجازی یک "پردازنده مبتنی بر نرم افزاره" (اگه راحت ترید بگید پردازنده مجازی!) که یک مجموعه دستورالعمل (instruction set) به نام Java bytecode رو ارائه می کنه و معمولا با عنوان java virtual machine یا jvm ازش نام برده میشه. میشه گفت ماشین مجازی جاوا یا jvm در نقش قلب پلتفرم جاوا (یا مغز، یا هر عضو حیاتی دیگه ای که مد نظرتونه!) ایفای نقش میکنه! یعنی در این حد نقش مهمی دارن! نور چشمی پلتفرم هستن ایشون راستش به طور کلی نیازی نیست که شما بدونید jvm چیه، یا حتی چی کار میکنه، تا بتونید با زبان جاوا برنامه بنویسید! اما از سویی، اگه خودتونو با فعالیت های درونی یه ماشین آشنا کنید به افزایش درک و بینش کلی خودتون کمک میکنه و از سوی دیگه، شما میتونید جلوی خیلی از مشکلات اجرایی رو بگیرید! (در واقع اکثر این مشکلات ساده هستن اگه کمی نسبت به jvm و عملکردش درک پیدا کنید!) ببینید دوستان، جاوا یک زبان برنامه نویسی سطح بالاست. البته منظور از سطح بالا این نیست که BMW زیر پاشونه زبان های برنامه نویسی سطح بالا به نوعی طراحی شدن که دستوراتشون نزدیک به زبان طبیعی ما (البته ما نه، اونا! یعنی زبان انگلیسی) باشن، و البته در عین حال قابلیت تفسیرپذیری آسونی هم برای ماشین داشته باشن. همونطور که احتمالا میدونید، دستورات یک زبان برنامه نویسی سطح بالا کاملا متفاوتن با کد ماشین (native code)؛ کد ماشین یک مجموعه از دستورالعملاتیه که پردازنده اون ماشین برای ساخت و اجرای برنامه استفاده میکنه (به مجموعه این دستورالعملات میگن instruction set). در واقع هر instruction set یک مجموعه ست از دستورالعملات از پیش تعریف شده که برای معماری پردازنده داده شده معتبره! یعنی اون پردازنده میتونه این دستورالعملات رو درک و اجرا کنه!

عزیزان دلی که ما بهشون میگیم زبان برنامه نویسی سطح بالا در واقع یک یا چندین سطح انتزاع از کد ماشین رو برامون فراهم میکنن. برای همین قبل از اینکه دستوراتشون قابلیت اجرا پیدا کنن، کد سطح بالا اول باید تفسیر شه! وظیفه این تفسیر به عهده برنامه ای به نام کامپایلره؛ پس کامپایلر شد برنامه ای که سورس کد نوشته شده با یه زبان برنامه نویسی سطح بالارو تبدیل میکنه به کدی از یک زبان برنامه نویسی سطح پایین تر که معمولا بهش object code هم گفته میشه! خیلی از رابط های برنامه نویسی به شکل AOT عمل کامپایل رو برای یک پلتفرم خاص انجام میدن (Ahead-of-time). یعنی "قبل از اجرا" کامپایلر کد سطح بالارو مستقیما تبدیل میکنه به کد ماشین. این کار باعث میشه که برنامه در زمان اجرا کارآمدی بالایی پیدا کنه (چون native code ماشین به طور خالص در حال اجراست!)، اما به مراتب سازگاری کمتری با پلتفرم های مختلف خواهد داشت!

اما متاسفانه یا خوشبختانه (جلوتر میگم کدوم!) جاوا از این کارا بلد نیست! به جاش جاوا با یک زبان سطح میانی به نام جاوا بایتکد که برای jvm ساخته و پرداخته شده کار میکنه. همونطور که بالا اشاره کردم جاوا بایتکد instruction set هستش برای jvm، و این یعنی jvm به عنوان یه پردازنده مجازی، تنها قادر به درک و اجرای دستورات جاوا بایتکده.

وقتی که شما برنامه ی جاواتونو نوشتید، کامپایلر جاوا سورس کدتون رو به جاوا بایتکد ترجمه میکنه و بایتکد برنامه رو داخل یک فایل (البته نه الزاما یکی!) با فرمت-فایل class. ذخیره میکنه! به این فایل ها معمولا classfile گفته میشه. خب این کار کد سطح بالاتون رو تا "یک سطح" به کد ماشین نزدیک تر میکنه، اما هنوز این کد (جاوا بایتکد) قابلیت اجرا توسط ماشین رو نداره (کد native ماشین نیست)! بایتکدی که به عنوان خروجی کامپایلر تولید میشه یک مجموعه از دستورالعملات بسیار بهینه شده و جمع و جوره که همونطور که گفتم توسط jvm قابل درک و اجراست (کد native ماشین مجازی جاواست)! پس؟ پاس داده میشه به jvm! مفسری که داخل jvm تعبیه شده میاد و "در زمان اجرا" (Just-in-time) بایتکد برنامه رو کامپایل میکنه به کد ماشین تا در نهایت ماشین قادر به اجرای برنامه ی جاوامون بشه!

خب دلیل این همه اضافه کاری چیه؟ (پاسخ به چرای اولتون)

1. همین که کد خروجی کامپایلر جاوا مستقیما توسط ماشین قابل اجرا نیست خودش یعنی امنیت! چرا؟ چون برنامه های مخرب نمیتونن برای اجرای خودکار ازش استفاده کنن! البته دلایل امنیتی دیگه ای هم وجود داره اما در همین حد که به طور کلی یه ایده از "امنیت" تو ذهنتون داشته باشید کافیه.

2. اگه کد جاوای شما قراره توسط کامپایلر جاوا به دستورات بایتکد ترجمه شه، و همچنین دستورات بایتکد قراره توسط jvm تفسیر و اجرا شه، آیا دیگه نیازی هست ما نگران این باشیم که "آیا برنامه مون با فلان محیط یا فلان سیستم عامل هم سازگار هست یا نه... ؟!" خیر. چرا؟ چون تنها کافیه ما روی اون محیط یا سیستم عامل، پلتفرم جاوارو پیاده سازی کنیم! در واقع دیگه برنامه ی ما داره به نوعی مستقل از پلتفرم (platform indepedent) عمل میکنه، چون ما داریم مسئولیت تعامل برنامه خودمون با پلتفرم native رو به jvm واگذار میکنیم، بقیه ش دیگه نه به ما مربوطه نه به شما! و این به جاوا قابلیت حمل میده؛ بهتره اینم بدونید که قابلیت حمل یکی از اصلی ترین اهداف ایجاد زبان جاوا بود! قبل از جاوا، اگه شما یه برنامه برای یک سیستم مبتنی بر یونیکس مینوشتید غیر ممکن بود که بتونید همون برنامه رو روی یک سیستم ویندوزی اجرا کنید (چون دیگه اون برنامه تنها برای سیستم های مبتنی بر یونیکس native بود).

- راستی، بالاخره متاسفانه یا خوشبختانه؟! آیا به قول خودتون یه کامپایل سر راست به کد ماشین خیلی کارآمدتر از استفاده از مفسر نیست؟!

چرا هست! ولی راستش بهش نیازی نداریم! ببینید یکی دیگه از اهداف ایجاد زبان جاوا (وای چرا تموم نمیشن؟ ) هدف قرار دادن محیط وب بود؛ یعنی نوشتن برنامه هایی که قراره تحت وب اجرا شن! پس سرعت نمیتونه ملاک خیلی مهمی برامون باشه، چون تو محیط وب در درجه اول این شبکه ست که تعیین کننده ی سرعت اجرای برنامه ست. از طرفی چون قراره این برنامه تحت وب باشه پس باید قابلیت اجرا شدن رو همه پلتفرما رو داشته باشه (چون هر کسی از هر جای دنیا با هر پلتفرمی ممکنه برنامه مارو اجرا کنه!)، و اینجاست که شما یه بار دیگه اهمیت platform indepedent بودن برنامه های جاوارو درک میکنید. تازه شم، اوراکل به قدری بهینه سازی های مختلفی روی jvm، جاوا بایتکد،کامپایلر و به طور کلی روی jdk اعمال کرده (و حتی الان که شما در حال خوندن این متنید مردان اوراکل بیدارن و در حال بهینه سازی جاوا ) که واقعا هیچ تفاوتی در حالت عادی و غیر عادی (!) قابل لمس نیست.

بازی سازی در اندروید

همونطور که تو تصویر بالا قابل مشاهده س، کد native یه برنامه یونیکس/ویندوز تنها میتونه رو یه ماشین مبتنی بر یونیکس/ویندوز اجرا شه؛ اما شما میتونید کد native یه برنامه جاوا (یعنی جاوا بایتکد) رو با استفاده از پلتفرم جاوا بر روی هر 2 ماشین اجرا کنید!

یه کوچولو حرف حساب: امکانش وجود داره که شما بتونید portability یا قابلیت حمل یک برنامه جاوارو از بین ببرید! برای مثال ممکنه برنامه ای بنویسید که دنبال فایل هایی بگرده که تنها رو یک سیستم عامل خاص پیدا میشه، مثل cmd.exe! یا امکان داره از JNI استفاده کنید، که به طور موثر بهتون اجازه میده کدهای کامپایل شده c و c++ رو داخل یک کلاس قرار بدید. یا حتی امکان داره از کنوانسیون هایی استفاده کنید که تنها برای یک سیستم عامل خاص کار میکنن، مثلا فرض این که ":" دایرکتوری هارو جدا میکنه! اما به طور کلی براتون تضمین شده که شما هرگز مجبور به کامپایل مجدد برنامه خودتون برای یک ماشین متفاوت نخواهید بود، مگه اینکه در حال انجام یه کار خیلی خاص باشید (مثل JNI).

خب داشتیم از پلتفرم جاوا میگفتیم که تشکیل شده از یک ماشین مجازی و یک محیط اجرایی. راجع به کلیت jvm صحبت کردیم (البته هنوز کار داریم باهاش، قراره یه کوچولو عملکردشم بررسی کنیم ✌)، اما محیط اجرایی چیست؟! محیط اجرایی پلتفرم جاوا یک کالکشن بزرگ از کتابخونه های از پیش ساخته شده ست. در زبان جاوا، کتابخونه ها معمولا به شکل فایل های JAR پکیج بندی میشن. فرمت-فایل jar. یک فرمت آرشیوی هستش که بر روی فرمت فایل ZIP ساخته شده! هر کدوم از این کتابخونه ها (فایل های JAR) شامل یک مجموعه از classfileهای مرتبط هستن که قابلیت های بسیار بسیار مفیدی رو برای ارائه دارن. از عملیات های ریاضی (مثلثات، به عنوان مثال) بگیرید تا ارتباطات شبکه، امنیت، ایجاد XML، دسترسی به Database و ...! معمولا از این کتابخونه با عنوان java class library یا java API هم نام برده میشه. در واقع این همون قسمت از پلتفرم جاواست که وظیفه کوتاه کردن کدنویسی شما و آسون کردن برنامه نویسی با جاوارو به عهده داره!

راستی این همه گفتیم جاوا بایتکد، گفتم یه نمونه بایتکد نشونتون بدم که یه ذهنیتی ازش داشته باشید! به عنوان مثال اگه فرض کنید کد پایین داخل یک متد باشه:

outer:
for (int i = 2; i < 1000; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0)
continue outer;
}
System.out.println (i);
}
Click and drag to move


تقریبا میشه گفت کامپایلر جاوا یه همچین بایتکدی رو تولید میکنه:

0: iconst_2

1: istore_1

2: iload_1

3: sipush 1000

6: if_icmpge 44

9: iconst_2

10: istore_2

11: iload_2

12: iload_1

13: if_icmpge 31

16: iload_1

17: iload_2

18: irem

19: ifne 25

22: goto 38

25: iinc 2, 1

28: goto 11

31: getstatic #84; // Field java/lang/System.out:Ljava/io/PrintStream;

34: iload_1

35: invokevirtual #85; // Method java/io/PrintStream.println:(I)V

38: iinc 1, 1

41: goto 2

return : 44

البته به هیچ وجه لازم نیست که یک developer جاوا، بایتکد جاوارو درک کنه؛ با این حال اساتید فن توصیه کردن که درک بایتکد و اینکه چه بایتکدی احتمال داره توسط کامپایلر جاوا تولید شه به همون روشی به برنامه نویس جاوا کمک میکنه که دانش اسمبلی به برنامه نویس سی یا سی پلاس پلاس

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

https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

خب تو این قسمت اختصاصا میریم سراغ jvm، یه بررسی کوچیک ازش داریم و بعدش میتونیم کدنویسیو شروع کنیم :) امروز احتمالا رو 3تا برنامه ساده جاوا تمرکز میکنیم و ویژگی هاشون رو با هم بررسی میکنیم. برای جلوگیری از اتلاف وقت بیشتر تصمیم دارم جلسه آینده تقریبا به طور کامل سینتکس و نکات زبان جاوارو تا قبل از شروع مبحث شی گرایی ارائه بدم، در کنارش البته به مقدار لازم برنامه های نمونه هم خواهیم داشت. کار خیلی سنگینیه برای یک جلسه اما شدنی! تنها چیزی که یه کمی نگرانم میکنه زمان آماده سازیشه که فکر کنم منطقیه طول بکشه. اگه دیدم قراره انتظارتون خیلی طولانی شه حتما تو 2 جلسه ارائه میدم.

معماری jvm به نوعی هستش که کنترل دقیق داره بر اقداماتی که یک برنامه جاوا انجام میده. هر برنامه تو یک محیط تست ایزوله شده اجرا میشه و jvm تضمین میکنه که اون برنامه به فایل های محلی سیستم، به processها و شبکه بندی دسترسی داره بدون اینکه ملزم به گرفتن اجازه خاصی باشه! به طور کلی jvm شامل دو زیر-سیستم اصلی هستش، Class Loader (مسئول خوندن classfileها و بارگذاری کردن اونا رو حافظه) و Execution Engine (مسئول اجرا کردن دستورات از روی classfileهای بارگذاری شده). حافظه ای که داریم راجع بهش حرف میزنیم همون حافظه RAM سیستم هستش که jvm برای کار خودش رزرو کرده!

اما classloaderها؛ همونطور که اشاره کردم وظیفه classloader اینه که محل قرارگیری پکیج هارو پیدا کنه، محتویاتشون رو بخونه و classfileهای داخلشون رو بارگذاری کنه روی حافظه. علاوه بر پکیج یا پکیج های خود برنامه، یعنی اونایی که خودمون نوشتیم (هر پکیج میتونه شامل یک یا چندین کلاس باشه!)، برنامه های جاوا میتونن از پکیج های خارجی هم استفاده کنن، یعنی کتابخونه هایی که توسط کس یا کسانی دیگه نوشته و برامون فراهم شده! فرایند اجرا به این ترتیبه که یک ابزار مشخصی به نام javac میاد jvm رو بارگذاری میکنه و استارتش رو میزنه، در قدم بعدی classfile اصلی برنامه رو شناسایی میکنه و به jvm پاس میده. اینجاست که کامپوننت classloader وارد میشه و classfile پاس داده شده رو روی حافظه بارگذاری میکنه.

بعد از اینکه classfile بارگذاری شد، کامپوننت دیگه ای داخل jvm به نام bytecode verifier اطمینان حاصل میکنه که بایتکد classfile ما معتبره و علاوه بر اون امنیت پلتفرم nativeمون رو با خاطر مواجه نمیکنه! بله! پلیس jvm هم داریم! فک کردین الکیه پس؟ اتفاقا ایشون بسیار کامپوننت بی اعصابی تشریف دارن و اگه مشکلی با بایتکد classfile پیدا کنن به اجرای jvm خاتمه میدن! با فرض این که بایتکد classfileمون بچه خوبی باشه و مشکل خاصی برامون ایجاد نکنه، کامپوننت interpreter یا مفسر jvm شروع میکنه دونه به دونه دستورات جاوا بایتکد رو تبدیل کردن به کد native معادل. یعنی کدی که توسط پردازنده فیزیکی کامپیوتر قابل درک و اجرا باشه! این همون مرحله just-in-time compilation هستش که بالا بهش اشاره کردم! جالبه بدونید که jvm قبل از نسخه 1.2 جاوا، تو همین مرحله (یعنی مرحله تفسیر) از JIT compilation استفاده نمیکرد، به جاش مفسر خودش اقدام به اجرای جاوا بایتکد میکرد!

در طول اجرای JIT compilation ممکنه مفسر با یه درخواست برای اجرای بایتکد یک classfile دیگه مواجه شه! وقتی این اتفاق می افته، مفسر خیلی محترمانه از classloader درخواست میکنه که اون classfile رو بارگذاری کنه و بعدش از bytecode verifier میخواد تا چک امنیتی خودشو انجام بده تا بتونه عملیات interpreting خودشو آغاز کنه! همچنین در طول اجرا ممکنه دستورات بایتکد درخواست کنن که jvm یک فایلی رو باز کنه، یا یک چیزی رو روی screen نمایش بده، یا به طور کلی باید یک taskی رو انجام بده که نیازمنده تعامل با پلتفرم native ماست! در این صورت jvm میاد و اون درخواست رو توسط پل ارتباطی JNI خودش (Java-native-interface) به پلتفرم native منتقل میکنه!

بازی سازی در اندروید


- واقعا لازم بود این همه تئوری گفته شه؟!

بله لازم بود! اولا که من چیز زیادی نگفتم، در مجموع 4-5تا pm شد، بنده میتونم یه دوره آموزشی جداگانه در خدمتتون باشم و فقط راجع به jvm براتون حرف بزنم. اگه یه کتاب با موضوع بحث jvm دیده باشید منظورمو متوجه میشید! مثال عرض میکنم، Inside the java 2 virtual machine از bill venners یکی از بهترین و مطرح ترین کتاب های نوشته شده در این زمینه، نزدیک به 700 صفحه ست! باور بفرمایید با یک دوره هم نمیشه همشو گفت! (اگه خیلی علاقه مندید این کتابو به شدت پیشنهاد میکنم، چون واقعا خوندنش لذت بخشه!)

ثانیا لطفا انقد از تئوری بدتون نیاد! خیلی از اساتید کدنویسی اگه ذره ای عمق داده شه به کارشون عین گُل گیر میکنن تو گِل! چرا؟ چون از اولش سطحی شروع کردن و سطحی هم ادامه دادن، در همون سطح هم خواهند موند!

یه مقاله جالبی پیتر نورویگ، نویسنده کتاب هوش مصنوعی: رهیافتی نوین (یکی از اصلی ترین و محبوب ترین کتاب های نوشته شده در این زمینه) سال 2001 نوشته بود با عنوان "teach yourself progrmming in ten years!" (ایشون الان در حال حاضر مدیر بخش پژوهش گوگل هم هستن!)

من یه قسمت از ترجمه فارسیش رو که آقای عسگری زحمتشو کشیدن اینجا براتون میذارم، شک نکنید که جالبه:

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

pubdate: after 1992 and title: days and (title: learn or title: teach yourself)

یعنی کتاب هایی که از سال 1992 تا الان چاپ شده و در عنوانشان کلمات days و "یادگیری یا خودآموز" وجود دارد. نتیجه شامل 248 مورد بود. 78 کتاب اول کتاب های مربوط به کامپیوتر بودند. عبارت days را با hours جایگزین کردم؛ نتایج مشابه قبلی بود: 253 مورد که 77 تای اول در مورد کامپیوتر بودند. از 200 کتاب صدر نتایج جستجو (در کل) 96 درصد مربوط به کامپیوتر بود.

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

خب ببینیم عنوانی مثل "آموزش پاسکال در 3 روز" چه معنی ای دارد:

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

پاسکال: در 3 روز شاید بتوانید سینتکس پاسکال را یاد بگیرید (آن هم به شرطی که قبلا با یک زبان مشابه کار کرده باشید) اما زیاد نمی توانید درباره ی کاربرد زبان یاد بگیرید. یعنی اگر قبلا با بیسیک برنامه نویسی کرده باشید، یاد می گیرید که برنامه ها را در پاسکال ولی با روش بیسیک بنویسید اما نقاط ضعف و قوت پاسکال را یاد نمی گیرید. به قول آلن پرلیس: "زبانی که طرز فکر شما را درباره ی برنامه نویسی تغییر ندهد، ارزش یادگیری ندارد". ممکن است شما بخواهید قسمتی از پاسکال (یا هر زبان دیگری) را یاد بگیرید تا بتوانید از ابزار خاصی استفاده کرده و کار مشخصی را انجام دهید؛ در این صورت دیگر برنامه نویسی یاد نمی گیرید، بلکه یاد می گیرید چطور آن کار مشخص را انجام دهید.

3 روز: همانطور که در بخش بعدی می بینید ، این مدت کافی نیست.

محققان نشان دادند که برای متخصص شدن در بسیاری از زمینه ها (از شطرنج گرفته تا آهنگ سازی ، اپراتوری تلگراف ، نقاشی ، نواختن پیانو ، شنا ، تنیس ، عصب شناسی ، ...) حدود 10 سال زمان لازم است. نکته ی مهم انجام کار پیوسته و با توجه است، نه صرفا کاری را مدام تکرار کردن، بلکه به چالش کشیدن خودتان با کارهایی که فراتر از توانایی فعلی تان است و تحلیل کارایی تان قبل و بعد از انجام آن کار و اصلاح اشتباهاتتان. و بعد تکرار کنید. و دوباره تکرار کنید. هیچ میانبری وجود ندارد: حتی موزارت که در 4 سالگی اعجوبه ای در موسیقی بود، 13 سال طول کشید تا بتواند اولین کار حرفه ای و جهانیش را بسازد. گروه موسیقی بیتلز در سال 1964 با وارد شدن به صحنه ی موسیقی اکثر کارهایشان جزو کارهای محبوب (و به قولی "نامبر وان") بودند ولی فراموش نکنید که اعضای گروه از سال 1957 در کلوب های کوچک لیورپول و هامبورگ فعالیت می کردند و اولین موفقیت بزرگشان (Sgt. Peppers) در سال 1967 عرضه شد. در یک مطالعه بر روی دانش آموزان در آکادمی برلین، محققان اعضای برتر، متوسط و پایین کلاس را مقایسه کرده و از آن ها پرسیدند که چقدر تمرین کرده اند:

همه (از هر سه گروه) نواختن را از حدود 5 سالگی شروع کرده و در سال های اول هر کس به یک میزان فعالیت می کرد (حدود 2 یا 3 ساعت در هفته) اما در حدود 8 سالگی تفاوت های واقعی نمایان شد. کسانی که در کلاس هایشان بهترین بودند، بیش از بقیه تمرین می کردند: 6 ساعت در هفته در سن 9 سالگی، 8 ساعت در 12 سالگی، 16 ساعت در 14 سالگی و الی آخر تا سن 20 که هفته ای بیش از 30 ساعت کار می کردند. در سن 20 سالگی افراد برتر نزدیک به 10000 ساعت از عمرشان را به تمرین گذرانده بودند. دانش اموزان رده بعدی حدود 8000 ساعت و دانش اموزان معمولی (معلمین موسیقی در آینده!) حدود 4000 ساعت.

شاید هم 10000 ساعت آن عدد جادویی باشد نه 10 سال. به نظر ساموئل جانسون (1709-1784) زمان بیشتری لازم است: "برتری در هر رشته ای فقط با یک عمر کار به دست می آید و با قیمت کمتری قابل خرید نیست"

امیدوارم به قدر کافی motivated ،inspired و از اینجور چیزا شده باشید...

برسیم به کار خودمون. فکر میکنم تا اینجا به قدر کافی راجع به کلیت ماجرا صحبت شد. دیگه کم کم میتونیم بریم سراغ عمل تقریبا مرسومه که استارت یک زبان برنامه نویسی و ابزارشو با نوشتن، کامپایل کردن و اجرای یه برنامه ساده که پیام Hello, World! رو به خروجی میبره میزنن. احتمالا میدونید! نقطه شروع این رسم هم برمیگرده به کتاب The C Programming Language اثر دنیس ریچی (خالق زبان c) و برایان کرنیگان. من معمولا آدم پایبندی به رسم و رسوم نیستم، اما واقعا در این زمینه دلیلی بر ناپایبندی نمیبینم پس بهتره خیلی دنیس-ریچی-وارانه ادامه بدیم!

public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("Hello, World!");
}
{
Click and drag to move


این برنامه کوتاه 7 خطی خیلی حرفا راجع به زبان جاوا باهاتون داره! من مختصراً هر کدوم از ویژگی هارو توضیح میدم، توضیحات مفصل تر میمونه برای جلسه بعد. پس لطفا اگه یه سری چیزا براتون گنگ بود با ذهن باز باهاشون برخورد کنید! فعلا یه درک 50 درصدی هم برام کافیه!

تو خط اول سورس کد، داره یه کلاس تعریف میشه و همچنین اسمش گذاشته میشه HelloWorld. این که کلاس چیه قرار نیست الان روش صحبت شه! در حال حاضر تصورتون از کلاس یه container، یه حامل، برای توصیف برنامه مون باشه! یعنی ما میایم یک کلاس تعریف میکنیم و برنامه مون رو داخلش مینویسیم! توجه کنید جاوا یک زبان برنامه نویسی کاملا شی گراست، هیچ برنامه ای بدون تعریف حداقل یک کلاس قابل تعریف نیست! منظور از public چیست؟ public داره سطح دسترسی به کلاسمون رو مشخص میکنه! احتمالا معنیش رو میدونید، به فارسی میشه "عمومی"، یعنی هر کلاس دیگه ای میتونه به کلاسمون دسترسی داشته باشه چون ما کلاسمون رو عمومی تعریف کردیم! ادامه تعریف کلاس بین یه پرانتز باز و یه پرانتز بسته انجام میگیره! پس تا اینجاش شد:

public class HelloWorld
{

}
Click and drag to move

نکته مهم: کلمه class و کلمه public کلماتی کلیدی هستن در جاوا! کلمات کلیدی کلماتی هستند که برای یک زبان دارای معنی و مفهوم اند! یعنی جزء syntax اون زبان محسوب میشن! در واقع وقتی شما از این کلمات استفاده میکنید به نوعی دارید به جاوا میگید که یه کاری براتون انجام بده. خواستم شمارو به 2تا نکته دقت بدم:

1. شما نمیتونید از این کلمات برای نامگذاری اجزای برنامه تون استفاده کنید! مثلا نمیتونید بگید من میخوام به جای HelloWorld اسم کلاسمو بذارم class

2. جاوا زبانی case-sensitive هستش! یعنی چی؟ یعنی بین class و Class و clAss و ... تفاوت قائل میشه! وقتی میگم class یه کلمه کلیدیست در جاوا، یعنی دقیقا خود class! نه Class یا cLass! پس میتونید اسم کلاستونو هرکدوم از اینا بذارید

3. ببخشید شد 3تا دقت کنید کلمه کلیدی با کلمه رزرو شده تفاوت معنایی داره! تمامی کلمات کلیدی کلمات رزرو شده هستن، یعنی برای زبان جاوا رزرو شدن و شما نمیتونید استفاده شخصی ازشون بکنید! اما تمامی کلمات رزرو شده الزاما کلمه کلیدی نیستن! یعنی تمامی کلمات رزرو شده الزاما دارای معنی و مفهوم نیستن و قرار نیست حتما کاری انجام بدن! فعلا دوتا کلمه رزرو شده وجود داره داخل جاوا که کلمه کلیدی نیستن: goto و const. در هر صورت از اینام نمیتونید استفاده شخصی کنید!

ادامه میدیم:

بین این دوتا کاراکتر ({ }) اعلان یک متد انجام گرفته. تصورتون از متد دنباله ای از کد باشه که نامگذاری شده! این متد داخل کلاسمون main نامگذاری شده برای اینکه دقیقاً مشخص کنه نقطه شروع برنامه اینجاست! اجرای تمامی برنامه های جاوا با فراخوانی متد main آغاز میشه! یعنی jvm میاد و تو برنامه تون اول دنبال متد main میگرده و فراخوانیش میکنه! پس اگه نباشه در واقع برنامه تون نقظه شروعی نداره! هر متدی یک هدری داره که باعث تمایزش با یک متد دیگه میشه، و همچنین یک بلاک از کد که بین کاراکترهای { } قرار میگیره (مثل کلاس!). هدر هر متدی علاوه بر مشخص کردن نام متد، یک سری اطلاعات دیگه از ویژگی های اون متد رو برامون فراهم میکنه! برای مثال اینجا متد ما public هستش، static هستش و void. فعلا نمیتونم معنی دقیق هرکدومشون رو بهتون بگم، چون باید بیشتر از اینا بدونید تا براتون قابل درک باشه! اما یه توضیح مختصر و مفید چرا:

از public شروع کنیم. من public رو برای کلاس تقریبا براتون معنی کردم. متد main عضوی از کلاس HelloWorld ماست. وقتی عضو یک کلاس رو public تعریف میکنید معنیش اینه که قسمت های مختلف برنامه میتونن به این عضو دسترسی داشته باشن! متضاد public میشه private (خصوصی!). اگه من اینجا متدم رو private تعریف میکردم، هیچ عضوی از برنامه (اگه مستقل از کلاس باشه) نمیتونه بهش دسترسی پیدا کنه! (حتی با اینکه کلاسم public تعریف شده!) خب چرا public تعریف کردیم؟ به چه علت؟! همونطور که گفتم متد main نقطه شروع برنامه ست و قبل از هر چیز دیگه ای فراخوانی میشه. اگه private تعریف شه کدی که داخل jvm این متد رو فراخوانی میکنه، نمیتونه پیداش کنه و مفسر jvm ارور میده! (توجه کنید که برنامه کامپایل میشه!)

اما static؛ کلمه کلیدی static به متد main ما این اجازه رو میده که توسط jvm فراخوانی شه قبل از اینکه هیچ شی یا objectی از این کلاس بسازه! (اگه میدونید داستان چیه خوش به حالتون، اگه هم نه فقط رد شید لطفا! ) کلمه کلیدی void هم داره به کامپایلر میگه که قرار نیست متد main هیچ مقداری رو به عنوان خروجی برگردونه! بازم میگم، اگه همه اینا یه ذره براتون گیج کنندس نگران باشید. هم قراره بیشتر توضیح بدم و هم قراره برنامه هایی ببینید که درکشون رو براتون خیلی راحت تر کنه.

همونطور که 2-3 بار عنوان شد متد main متدی ست که زمانی که برنامه اجرا میشه فراخوانی میشه! هرگونه اطلاعاتی که شما لازم دارید تا به این متد پاس بدید، توسط متغیرهایی که بین دوتا پرانتر بعد از نام متد اومده دریافت میشه! نه فقط برای این متد، برای هر متدی! این متغیر یا متغیرها "پارامتر" نامیده میشن! اگه برای یک متدی هیچ پارامتری لازم نبود باید اون دوتا پرانتز رو بذارید ولی خب بینشون خالی میمونه! برای متد main تنها یک پارامتر وجود داره. String[ ] args،که داره یک پارامتر به نام args رو اعلان میکنه که یک آرایه از اشیای نوع String هستش. (هر آرایه = یک کالکشن از اشیای هم نوع!) اشیای نوع String یک دنباله از کاراکترهارو تو خودشون ذخیره میکنن! سوالی که ممکنه پیش بیاد اینه که اینجا args قراره چه آرگومان هایی دریافت کنه؟ (آرگومان همون عبارت یا مقداریه که ما پاس میدیم به متد و میره داخل پارامتر متد قرار بگیره! چرا برای args گفتم آرگومان ها؟ چون args یک آرایه ست! البته این آرایه میتونه تنها یدونه آرگومان دریافت کنه! لزومی وجود نداره که بگیم آرگومان ها.) آرگومان های خط فرمان در واقع اطلاعاتی هستن که مستقیما به دنبال نام کلاسمون موقع اجرا برنامه با خط فرمان و با یک فاصله نوشته میشن! در حال حاضر برنامه داره هیچ استفاده ای از این آرگومان ها نمیکنه! اما برنامه بعدیمون قراره در همین رابطه باشه و بیایم این آرگومان هارو به خروجی ببریم و نمایش بدیم! راستی هیچ چیز خاصی درباره نام args وجود نداره! میتونید بذاریدش koala یا panda

و اما خط بعدی کدمون که داخل بلاک متد main قرار گرفته. این خط از کد، جمله Hello, World! و به دنبالش یک خط جدید (new line) رو به خروجی میبره! در واقع عمل به خروجی بردن داره توسط متد از پیش ساخته شده println انجام میگیره! println متدیست که آرگومان یا آرگومان هایی که بهش پاس داده میشند رو چاپ میکنه! و حتما لازم نیست این آرگومان از جنس رشته باشه مثل "Hello, World!" بلکه خواهید دید قابلیت نمایش انواع دیگه ای از اطلاعات رو هم داره! همونطور که میبینید این خط از کد با System.out شروع شده که واقعا الان پیچیده س برای مفصل توضیح دادن. بهتره فعلا همون روش مختصر و مفیدمون رو پیش میگیریم: System یک کلاس از پیش تعریف شده ست (موجود در همون قسمت java class library) که به ما قابلیت دسترسی به سیستم رو میده و out جریان خروجی ایه که به کنسول متصل شده. به طور کلی System.out شی ایه که ما داریم استفاده میکنیم تا به جریان خروجی کنسول متصل شیم!

تنها نکته ای که باقی مونده اینه که اگه دقت کنید بعد از به اتمام رسیدن این دستور، ";" گذاشته شده. به طور کلی تمامی عبارات یا statementها در جاوا باید با ";" به پایان برسن! تنها دلیلی که ما برای بقیه خطوط برنامه مون از ";" استفاده نکردیم این بود که اونا statement نبودن

اما بریم سراغ برنامه بعدی:

public class DumpArgs
{
public static void main(String[] pear)
}
System.out.println("Passed arguments: ");
for(int i = 0; i < pear.length; i++)
System.out.println(pear[i]);
}
}
Click and drag to move


اینجا برای تنوع اسم پارامترمون رو گذاشتم گلابی که فک نکنید خبر خاصیه

قرارمون این بود که بیایم تو این برنامه آرگومان هایی که تو خط فرمان به پارامتر args سابق یا گلابی جدید پاس داده میشن چاپ کنیم! بسیار عالی! اسم کلاسمون رو گذاشتیم DumpArgs! چون این کلاس قراره یک سری آرگومان رو dump کنه (قرار بده) رو جریان خروجی کنسولمون. اگه کد رو بخونید و بیاید پایین متوجه میشید هیچ تفاوتی با کلاس قبلیمون نداره تا جایی که for شروع میشه. for یک حلقه تکراره. شما اگه نیاز داشته باشید یه کدی رو 100 بار اجرا کنید، لازم نیست 100بار اون کد رو بنویسید! به جاش میاید از حلقه های تکرار استفاده میکنید؛ ساختارهایی که بهتون اجازه میدن هر تعداد کدی رو که خواستید برای هر تعداد باری اجرا کنید! خب چرا ما اینجا از حلقه for استفاده کردیم؟ قراره چه کاریو تکرار کنیم؟ همونطور که گفتم پارامتر args یک آرایه یا یک کالکشن از اشیای نوع رشته ست. حلقه for به ما این امکان رو میده تا بتونیم هرکدوم از آیتم های آرایه مون رو بخونیم و نمایش بدیم. برای مثال اگه قرار شد آرایه مون 3تا آیتم ورودی دریافت کنه، حلقه for مارو مقدور میکنه تا از تکرار جلوگیری کنیم و دیگه 3 بار به طور جداگانه دستور خوندن و نمایش دادن عناصر آرایه رو ننویسیم.

داخل پرانتزهای حلقه forمون یک متغیر (مکانی از حافظه که میتونیم ازش برای ذخیره کردن چیزهای مختلفی استفاده کنیم!) از نوع عدد صحیح یا int (اینجا قراره داخل متغیرمون عدد صحیح ذخیره شه!) اعلان شده و مقدارش رو مساوی 0 قرار دادیم. این متغیر قراره حواسش باشه که حلقه مون تا کجا پیشرفت داشته یا چند بار تکرار شده، علاوه بر اون توسط i میتونیم به ورودی های آرایه مون دسترسی پیدا کنیم! بعد از این دستور یک ";" گذاشته شده و بعدش متغیر i رو با pear.length مقایسه کردیم، که تعداد ورودی های آرایه مون (طول آرایه) رو برمیگردونه! این قسمت از تعریف حلقه در واقع داره شرط خروج از حلقه رو مشخص میکنه! این دستور داره میگه تا جایی حلقه for رو تکرار کن که i کوچک تر از تعداد ورودی های آرایه مون باشه! یعنی زمانی حلقه به اتمام میرسه که مقدار i با pear.length برابر بشه! با هر بار تکرار حلقه یک بار دستور System.out.println که داخل بلاک حلقه for قرار داره اجرا میشه؛ این دستور رشته ذخیره شده در ورودی iام از آرایه args رو میخونه و روی خروجی کنسول نمایش میده! توجه کنید که ورودی هر آرایه با index صفر شروع میشه، به همین دلیل هم ما مقدار اولیه i رو صفر قرار دادیم. از طرفی چون index اولین ورودی آرایه 0 هستش، در نتیجه index آخرین ورودی آرایه مون pear.length - 1 خواهد بود! (pear.length تعداد عناصر آرایه ست. مثلا اگه 6تا عنصر داشته باشیم، چون index اولین عنصر 0 هستش، Index آخرین عنصر 5 خواهد بود!) بعد از اینکه یک بار دستور موجود درون بلاک حلقه اجرا شد، کنترل برنامه دوباره برمیگرده داخل پرانترهای حلقه for و اونجا ابتدا قسمت سوم حلقه یعنی i++ اجرا میشه. این دستور یک واحد به مقدار i اضافه میکنه! و بعد قسمت دوم حلقه for یعنی شرط خروج از حلقه، با مقدار جدید i بررسی میشه! دیگه نیازی نیست تکرار کنم اگه جایی رو متوجه نشدید اشکالی نداره؟!

اگه شما این برنامه رو با استفاده از IDE اجرا کنید به جایی نمیرسید! چون باید با استفاده از خط فرمان این کارو انجام بدید تا بتونید آرگومان هایی که میخواید رو از خط فرمان به پارامتر args پاس بدید! اما اصلا نیازی نیست درباره خط فرمان و این که چجوری میتونید یه برنامه رو از اونجا کامپایل و اجرا کنید توضیح بدم. به همین دلیل خودم براتون از اجرای این برنامه با cmd اسکرین شات گرفتم تا بتونید حداقل کلیت ماجرارو با چشاتون ببینید:

بازی سازی در اندروید


همونطور که قابل مشاهده س ابتدا برنامه رو بدون آرگومان اجرا کردم و به همین دلیل تنها دستور System.out.println اول برامون اجرا شد. چون هیچ آیتمی داخل args قرار نگرفته بود! اما بار دوم که آرگومان های i و love و java رو پاس دادم به args حلقه for برامون هر3تارو تو یک خط جدید چاپ کرد. البته دقت کنید اینجا اسم کلاسم رو Class گذاشتم و DumpArgs نیست! شما حتی میتونید این خروجی رو داخل یک فایل هم ذخیره کنید. برای مثال دستور زیر خروجی بالارو داخل یک فایل با نام output.txt ذخیره میکنه:

java Class i love java >output.txt

قبل از اینکه تصمیم بگیرم برنامه سوم رو هم بگم یا نه، چون کمی طولانیه،یه چیزی مهمی که در نظر داشتم این جلسه بهتون یاد بدم اینه که چجوری میتونید با اندروید استودیو برنامه های جاواتون رو اجرا کنید. این رو بگم و بعد اگه وقتی باقی موند به اون هم برسیم.

بازی سازی در اندروید


اندروید استودیو رو که باز کردید، یه پروژه جدید بسازید.

بازی سازی در اندروید

یه نام برای پروژه تون انتخاب کنید و یک company domain که فرقی نداره چی باشه

بازی سازی در اندروید

با همین شرایط next

بازی سازی در اندروید

رو blank activity باشه و next

بازی سازی در اندروید

Finish

بازی سازی در اندروید

File, New, New Module

بازی سازی در اندروید

Photo, java library, next

بازی سازی در اندروید

finish و دلخواه

بازی سازی در اندروید


به این قسمت اضافه شده اگه expand کنید

بازی سازی در اندروید

میتونید پکیج و کلاستون رو ببینید، اگه روی پکیج کلیک راست کنید میتونید از شاخه new یه کلاس جدید هم ایجاد کنید

ساخت بازی در اندروید

و در نهایت برای اجرای برنامه تون کافیه رو editor کلیک راست کنید و run .معمولا بار اول طول میکشه تا پنجره کنسول براتون بالا بیاد

دانلود دانلود PDF قسمت دوم آموزش بازی سازی در اندروید

قسمت بعدی قسمت سوم آموزش بازی سازی در اندروید

کلمات کلیدی