Ctrl+K

راه‌اندازی محیط توسعه

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


۱. پیش‌نیازها

پیش از آنکه بتوانید توسعه با توت فرنگی را شروع کنید، باید محیط توسعه خود را راه‌اندازی کنید. توت فرنگی بر روی .NET 8.0 ساخته شده، بنابراین SDK الزامی است. همچنین به یک ویرایشگر کد نیاز دارید — ما Visual Studio Code (VS Code) را توصیه می‌کنیم زیرا سبک، رایگان، چندسکویی است و از طریق افزونه‌ها پشتیبانی عالی از C# ارائه می‌دهد.

۱.۱ .NET 8.0 SDK

SDK دات‌نت کامپایلر، محیط اجرایی و ابزارهای خط فرمان مورد نیاز برای بیلد و اجرای پروژه‌های C# را فراهم می‌کند. توت فرنگی به طور خاص .NET 8.0 را هدف قرار داده، بنابراین باید این نسخه (یا نسخه سازگار بعدی) را نصب کنید.

لینک دانلود: https://dotnet.microsoft.com/en-us/download/dotnet/8.0

پس از دانلود و نصب، یک ترمینال (Command Prompt، PowerShell، یا هر شل در لینوکس/macOS) باز کنید و اجرا کنید:

dotnet --version

باید یک شماره نسخه که با 8. شروع می‌شود ببینید (مثلاً 8.0.xxx). اگر خطایی یا نسخه متفاوتی دیدید، SDK به درستی نصب نشده — مطمئن شوید پس از نصب ترمینال خود را ری‌استارت کنید و تأیید کنید که دستور dotnet در مسیر سیستم (PATH) شما قرار دارد.

۱.۲ Visual Studio Code

VS Code ویرایشگر پیشنهادی برای توسعه با توت فرنگی است. رایگان، متن‌باز و روی ویندوز، macOS و لینوکس اجرا می‌شود. در حالی که می‌توانید از هر ویرایشگر یا IDE دیگری (مانند Visual Studio یا JetBrains Rider) استفاده کنید، این راهنما VS Code را فرض می‌کند.

لینک دانلود: https://code.visualstudio.com/

افزونه‌های لازم VS Code

پس از نصب VS Code، باید افزونه C# Dev Kit را نصب کنید که موارد زیر را فراهم می‌کند:

  • IntelliSense — تکمیل خودکار و پیشنهادات کد هنگام تایپ
  • اشکال‌زدایی — تنظیم نقاط توقف، بررسی متغیرها و گام‌به‌گام اجرای کد
  • مدیریت پروژه — پنل Solution Explorer برای پیمایش پروژه‌ها و فایل‌هایتان

برای نصب:

۱. VS Code را باز کنید ۲. به پنل افزونه‌ها بروید (آیکون مربع در نوار کناری سمت چپ را کلیک کنید، یا Ctrl+Shift+X را فشار دهید) ۳. "C# Dev Kit" را جستجو کنید (منتشر شده توسط Microsoft) ۴. Install را کلیک کنید

اختیاری، ممکن است بخواهید نصب کنید:

  • افزونه C# (توسط Microsoft) — اگر از قبل با Dev Kit همراه نشده است
  • NuGet Package Manager — برای مرور و مدیریت بسته‌های NuGet از داخل VS Code

۲. نصب

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

۲.۱ افزودن منبع سفارشی NuGet

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

دستور زیر را در ترمینال خود اجرا کنید:

dotnet nuget add source https://nuget.sb-engine.ir/v3/index.json -n Strawberry

این دستور یک منبع NuGet جدید با نام "Strawberry" ثبت می‌کند که به nuget.sb-engine.ir اشاره می‌کند. پرچم -n یک نام دوستانه به آن می‌دهد تا بتوانید بعداً آن را شناسایی کنید. پس از اجرای این دستور، هر دستور dotnet add package یا dotnet restore نیز این منبع را برای بسته‌ها بررسی خواهد کرد.

توجه: اگر نیاز به تأیید منابع پیکربندی شده خود دارید، dotnet nuget list source را اجرا کنید.

۲.۲ ایجاد سولوشن و پروژه‌ها

ما یک سولوشن با دو پروژه ایجاد خواهیم کرد. این جداسازی عمدی است و از الگویی رایج در توسعه بازی پیروی می‌کند:

  • MyFirstGame — این پروژه منطق بازی مشترک شماست. این پروژه شامل زمینه بازی (Game Context)، صحنه‌ها، موجود‌ها (Entity)، جزءها (Component) و تمام کد گیم‌پلی شماست. با نگه‌داشتن این در یک پروژه مجزا (به جای قرار دادن مستقیم در برنامه دسکتاپ)، امکان استفاده مجدد از همان منطق بازی در سکوهای مختلف (دسکتاپ، اندروید، وب‌اسمبلی و غیره) فراهم می‌شود.

  • MyFirstGame.Desktop — این پروژه راه‌انداز دسکتاپ است. تنها کار آن راه‌اندازی و اجرای بازی شما در یک سکوی دسکتاپ (ویندوز، macOS یا لینوکس) است. این پروژه به پروژه بازی شما و بسته مختص دسکتاپ توت فرنگی ارجاع دارد.

بیایید همه چیز را قدم‌به‌قدم ایجاد کنیم.

مرحله ۱: ایجاد پوشه برای پروژه

mkdir MyFirstGame
cd MyFirstGame

مرحله ۲: ایجاد فایل سولوشن

dotnet new sln -n MyFirstGame

این فایلی با نام MyFirstGame.sln در پوشه فعلی ایجاد می‌کند. فایل سولوشن به عنوان ظرفی عمل می‌کند که پروژه‌های شما را گروه‌بندی می‌کند.

مرحله ۳: ایجاد پروژه مشترک بازی

dotnet new classlib -n MyFirstGame

این یک پروژه کتابخانه کلاس با نام MyFirstGame ایجاد می‌کند. ما از کتابخانه کلاس (نه برنامه کنسول) استفاده می‌کنیم زیرا این پروژه قرار نیست به تنهایی اجرا شود — منطق بازی را فراهم می‌کند که توسط پروژه‌های راه‌انداز مختص سکو مصرف خواهد شد.

مرحله ۴: ایجاد پروژه راه‌انداز دسکتاپ

dotnet new console -n MyFirstGame.Desktop

این یک پروژه برنامه کنسول با نام MyFirstGame.Desktop ایجاد می‌کند. این به عنوان نقطه ورودی که بازی شما را در سکوهای دسکتاپ راه‌اندازی می‌کند عمل خواهد کرد.

مرحله ۵: افزودن هر دو پروژه به سولوشن

dotnet sln add MyFirstGame/MyFirstGame.csproj
dotnet sln add MyFirstGame.Desktop/MyFirstGame.Desktop.csproj

مرحله ۶: افزودن بسته توت فرنگی به MyFirstGame

cd MyFirstGame
dotnet add package Strawberry
cd ..

این بسته اصلی Strawberry را به پروژه مشترک بازی شما اضافه می‌کند. این بسته شامل تمام انواع بنیادی است: Game، GameContext، Scene، Entity، Component، گرافیک، فیزیک، صدا و بیشتر.

مرحله ۷: افزودن Strawberry.Desktop و ارجاع به MyFirstGame در پروژه دسکتاپ

cd MyFirstGame.Desktop
dotnet add package Strawberry.Desktop
dotnet add reference ../MyFirstGame/MyFirstGame.csproj
cd ..

بسته Strawberry.Desktop شامل بکند مختص سکو برای سیستم‌عامل‌های دسکتاپ است — ایجاد پنجره، پردازش ورودی، راه‌اندازی محیط OpenGL و حلقه بازی برای ویندوز، macOS و لینوکس را مدیریت می‌کند. ارجاع پروژه به MyFirstGame به پروژه دسکتاپ اجازه می‌دهد به کلاس زمینه بازی و تمام منطق بازی‌ای که می‌نویسید دسترسی داشته باشد.

۲.۳ ساختار نهایی پروژه

پس از تکمیل تمام مراحل بالا، پوشه شما باید به شکل زیر باشد:

MyFirstGame/
├── MyFirstGame.sln
├── MyFirstGame/
│   ├── MyFirstGame.csproj
│   └── Class1.cs
└── MyFirstGame.Desktop/
    ├── MyFirstGame.Desktop.csproj
    └── Program.cs

۳. پیاده‌سازی

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

۳.۱ MyFirstGame — زمینه بازی (Game Context)

در توت فرنگی، زمینه بازی (Game Context) قلب بازی شماست. این مشخص می‌کند که بازی‌تان چگونه مقداردهی، به‌روزرسانی و رندر می‌شود. شما کلاسی ایجاد می‌کنید که از StdGameContext ارث‌بری کرده و متدهای آن را برای راه‌اندازی صحنه‌ها، موجود‌ها (Entity) و سیستم‌هایتان بازنویسی می‌کنید.

پروژه MyFirstGame را باز کنید و فایل Class1.cs که به طور خودکار تولید شده را حذف کنید — به آن نیازی نداریم. سپس فایل جدیدی با نام MyGameContext.cs در پوشه پروژه MyFirstGame با محتوای زیر ایجاد کنید:

using Strawberry.Components;
using Strawberry.Core;
using Strawberry.Graphics;
using Strawberry.Graphics.Layers;
using Strawberry.Graphics.ParticleSystem;
using Strawberry.Graphics.Text;
using Strawberry.Math;
using Strawberry.Sound;
using Color = Strawberry.Graphics.Color;

namespace Strawberry.Test
{
    public class MyGameContext : StdGameContext
    {
        public const float ppm = 32f;

        public MyGameContext() : base(1280, 720)
        {

        }

        public override void OnInitialize(IGameLauncher laucnher)
        {
            base.OnInitialize(laucnher);

            var size = GraphicsContext.GetScreenSize();
            Viewport viewport = new Viewport("Default", new Vector2(), size, new Vector2(), new Vector2(1280, 720));

            Scene scene = new Scene("Main", 1280, 720);
            scene.ClearColor = Color.CornflowerBlue;
            AddScene(scene);
            SetScene("Main");
            scene.Viewports[0] = viewport;
        }
    }
}

بیایید بررسی کنیم هر قسمت چه کاری انجام می‌دهد:

سازنده — base(1280, 720)

public MyGameContext() : base(1280, 720)

سازنده پایه StdGameContext دو عدد صحیح دریافت می‌کند که رزولوشن مجازی بازی شما را نشان می‌دهند — در این مورد، ۱۲۸۰ پیکسل عرض و ۷۲۰ پیکسل ارتفاع. این فضای مختصاتی است که منطق بازی شما در آن عمل می‌کند، مستقل از اندازه واقعی پنجره روی صفحه. توت فرنگی به طور خودکار رندر را برای تناسب با پنجره واقعی مقیاس می‌کند در حالی که نسبت ابعاد تعریف شده توسط این رزولوشن مجازی را حفظ می‌کند.

ppm — پیکسل بر متر

public const float ppm = 32f;

این ثابت مشخص می‌کند چند پیکسل معادل یک متر در دنیای فیزیک است. مقدار 32 به این معناست که ۳۲ پیکسل = ۱ متر. این توسط سیستم فیزیک برای تبدیل بین مختصات پیکسلی و واحدهای فیزیکی استفاده می‌شود. در حالی که ما در این مثال مینیمال از فیزیک استفاده نمی‌کنیم، تعریف این ثابت از ابتدا یک عادت خوب است.

OnInitialize — راه‌اندازی بازی

متد OnInitialize یک بار هنگام شروع بازی فراخوانی می‌شود. اینجاست که صحنه‌ها، viewportها، لایه‌ها، موجود‌ها (Entity) و هر چیز دیگری که بازی‌تان نیاز دارد را ایجاد می‌کنید. بیایید هر خط را بررسی کنیم:

var size = GraphicsContext.GetScreenSize();

این اندازه واقعی صفحه (یا پنجره) را از زمینه گرافیکی دریافت می‌کند. ما از این برای تنظیم اندازه viewport خود استفاده می‌کنیم.

Viewport viewport = new Viewport("Default", new Vector2(), size, new Vector2(), new Vector2(1280, 720));

یک Viewport ناحیه مستطیلی از صفحه را تعریف می‌کند که یک صحنه در آن رندر می‌شود. سازنده پنج پارامتر دریافت می‌کند:

پارامتر مقدار توضیحات
نام "Default" یک نام یکتا برای این viewport
موقعیت new Vector2() گوشه بالا-چپ viewport روی صفحه (۰, ۰ یعنی از بالا-چپ شروع می‌شود)
اندازه size ابعاد پیکسلی viewport (تنظیم شده روی اندازه کامل صفحه)
MinBounds new Vector2() مختصات حداقل قابل مشاهده در دنیای بازی
MaxBounds new Vector2(1280, 720) مختصات حداکثر قابل مشاهده — مطابق با رزولوشن مجازی
Scene scene = new Scene("Main", 1280, 720);

یک صحنه (Scene) ظرفی برای تمام اشیاء بازی شماست — موجود‌ها (Entity)، لایه‌ها، فیزیک و viewportها. سازنده یک نام و رزولوشن مجازی دریافت می‌کند. می‌توانید چندین صحنه داشته باشید (مثلاً صحنه منو، صحنه گیم‌پلی، صحنه تیتراژ) و بین آن‌ها جابجا شوید.

scene.ClearColor = Color.CornflowerBlue;

رنگ پاک‌سازی (Clear Color) رنگ پس‌زمینه‌ای است که هر فریم پیش از رسم هر شیء صفحه را پر می‌کند. Color.CornflowerBlue یک آبی روشن دلپذیر است — یک انتخاب کلاسیک برای پس‌زمینه بازی. می‌توانید این را روی هر رنگی که دوست دارید تنظیم کنید.

AddScene(scene);
SetScene("Main");

AddScene صحنه را در زمینه بازی ثبت می‌کند. SetScene به موتور می‌گوید کدام صحنه باید فعال و رندر شود. در این مورد، بلافاصله "Main" را به عنوان صحنه فعال تنظیم می‌کنیم.

scene.Viewports[0] = viewport;

هر صحنه مجموعه‌ای از viewportها دارد. با اختصاص viewport خود به اندیس 0، آن را viewport اصلی (و در این مورد، تنها viewport) این صحنه قرار می‌دهیم. صحنه از طریق این viewport رندر خواهد شد.

۳.۲ MyFirstGame.Desktop — نقطه ورودی

حالا بیایید راه‌انداز دسکتاپ را تنظیم کنیم. فایل MyFirstGame.Desktop/Program.cs را باز کنید و محتوای آن را با موارد زیر جایگزین کنید:

using Strawberry.Test;

namespace Strawberry.Desktop.Test
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            MyGameContext gameContext = new MyGameContext();
            Game game = new Game();
            game.Run(gameContext, new GameLauncher(false));
        }
    }
}

در اینجا هر قسمت چه کاری انجام می‌دهد:

[STAThread]

این ویژگی (Attribute)، ترد اصلی را به عنوان ترد Single-Threaded Apartment علامت‌گذاری می‌کند، که توسط برخی سیستم‌های پنجره‌ای دسکتاپ (به خصوص در ویندوز) الزامی است. این تضمین می‌کند که اجزای COM که توسط زیرسیستم‌های پنجره‌ای و رندر استفاده می‌شوند به درستی کار کنند. همیشه این ویژگی را روی متد Main خود در پروژه‌های دسکتاپ نگه دارید.

MyGameContext gameContext = new MyGameContext()

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

Game game = new Game()

کلاس Game محیط اجرایی اصلی موتور است. حلقه بازی، زمان‌بندی و هماهنگی بین زمینه بازی و بکند مختص سکو را مدیریت می‌کند.

game.Run(gameContext, new GameLauncher(false))

این بازی را شروع می‌کند. دو پارامتر دریافت می‌کند:

  • gameContext — زمینه بازی ما، که به موتور می‌گوید چگونه بازی را مقداردهی و به‌روزرسانی کند
  • new GameLauncher(false) — یک نمونه GameLauncher پیکربندی شده برای دسکتاپ. پارامتر false نشانگر آن است که بازی به صورت تمام صفحه اجرا نشده و یک پنجره با حاشیه و نوار عنوان (Title bar) باز می شود.

۳.۳ مهم: راه‌اندازهای مختص سکو

کد بالا از GameLauncher استفاده می‌کند که راه‌انداز مختص دسکتاپ است. این راه‌انداز یک پنجره بومی ایجاد می‌کند، محیط OpenGL را راه‌اندازی کرده و ورودی دسکتاپ (کیبورد، ماوس، گیم‌پد) را پردازش می‌کند. این راه‌انداز فقط در سکوهای دسکتاپ (ویندوز، macOS و لینوکس) کار می‌کند.

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

سکو نوع راه‌انداز توضیحات
دسکتاپ (ویندوز/macOS/لینوکس) Strawberry.Desktop.GameLauncher یک پنجره دسکتاپ بومی با رندر OpenGL ایجاد می‌کند
اندروید Strawberry.Android.GameLauncher با چرخه ح فعالیت اندروید و ورودی لمسی یکپارچه می‌شود
وب‌اسمبلی (وب) Strawberry.Web.GameLauncher بازی را در مرورگر با استفاده از WebGL و HTML5 canvas اجرا می‌کند

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

  • MyFirstGame.Android — از Strawberry.Android.GameLauncher استفاده کرده و به عنوان برنامه اندروید بیلد می‌شود
  • MyFirstGame.Web — از Strawberry.Web.GameLauncher استفاده کرده و به وب‌اسمبلی کامپایل می‌شود

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

۳.۴ اجرای بازی

برای بیلد و اجرای بازی خود، یک ترمینال در پوشه ریشه MyFirstGame (جایی که فایل .sln قرار دارد) باز کنید و اجرا کنید:

dotnet run --project MyFirstGame.Desktop

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

از اینجا، می‌توانید شروع به افزودن موجود‌ها (Entity)، جزءها (Component)، چهره‌ها (Sprite)، فیزیک، صدا و تمام امکانات دیگر توت فرنگی برای ساخت بازی خود کنید. برای راهنمایی درباره هر سیستم، بقیه مستندات را بررسی کنید.


توسعه بازی خوشبخت با توت فرنگی!