এক্সএনএ-তে, আমি কীভাবে একটি বড় 2D বিশ্বের মানচিত্রের অংশগুলি গতিশীলভাবে লোড করব?


17

আমি একটি বিশাল বিশ্বের মানচিত্র বিকাশ করতে চাই; আকারে কমপক্ষে 8000 × 6000 পিক্সেল। আমি এটিকে 800 × 600-পিক্সেল পিএনজি চিত্রের 10 × 10 গ্রিডে ভেঙেছি। মেমরির মধ্যে সমস্ত কিছু লোড করা এড়াতে, গ্রিডে প্লেয়ারের অবস্থানের উপর নির্ভর করে চিত্রগুলি লোড এবং আনলোড করা উচিত।

উদাহরণস্বরূপ, পজিশনে প্লেয়ারটি এখানে (3,3):

প্লেয়ার এ (3,3)

তিনি যখন ডান দিকে যান, ডানদিকে (4,3)তিনটি চিত্র বরাদ্দ করা হয়েছে এবং ডানদিকে তিনটি চিত্রকে বামে বাম দিকে সরানো হয়েছে :

প্লেয়ার সরানো হয়েছে (4,3)

গ্রিডের প্রতিটি কক্ষের ভিতরে সম্ভবত একটি থ্রেশহোল্ড থাকা উচিত যা লোডিং এবং আনলোড লোকে ট্রিগার করে। লোডিং সম্ভবত পৃথক থ্রেডে হওয়া উচিত।

আমি কীভাবে এমন একটি সিস্টেম ডিজাইন করব?


1
দ্রুত পরামর্শ: আপনি এখানে দুটি প্রশ্ন পেয়েছেন, "আমি কীভাবে গেমায় গতিশীলভাবে টাইলস লোড করব" এবং "এক্সবক্স 360 এর জন্য আমি কীভাবে এক্সএনএ-তে থ্রেডিং করব"। এই পোস্ট থেকে ওএস-নির্দিষ্ট বিভাগগুলিকে সরিয়ে ফেলুন - টাইললোডিং কোডটি এক্সবি 360, লিনাক্স এবং নিন্টেন্ডো ওয়াইতে অভিন্ন হবে - এবং এক্সবক্স 360-এ থ্রেডিংয়ের জন্য একটি নতুন পোস্ট তৈরি করবে।
জোর্বাথুত

আপনার আসল সমস্যা সম্পর্কে একটি প্রশ্ন হিসাবে, এটি কি মসৃণ-স্ক্রোলিং মানচিত্র, বা পৃথক নন-স্ক্রোলিং স্ক্রিনগুলির একটি সিরিজ?
জোর্বাথুত

যদি আমি "স্মুথ-স্ক্রোলিং মানচিত্র" বুঝতে পারি তবে হ্যাঁ, এটি। প্রশ্ন পৃথক করার জন্য, আমি এটি সম্পর্কে ভেবেছিলাম কিন্তু কিন্ডা ফলস্বরূপ প্রশ্ন জিজ্ঞাসা করতে দ্বিধাগ্রস্থ। কিন্তু, আমি এখন এটি করব।
pek

উত্তর:


10

এখানে সমাধানের জন্য কয়েকটি সমস্যা রয়েছে। প্রথমটি কীভাবে টাইলস লোড এবং আনলোড করা যায়। ডিফল্টরূপে কন্টেন্টম্যানেজার আপনাকে নির্দিষ্ট সামগ্রীর টুকরো আনলোড করতে দেবে না। এটির একটি কাস্টম বাস্তবায়ন, তবে:

public class ExclusiveContentManager : ContentManager
{
    public ExclusiveContentManager(IServiceProvider serviceProvider,
        string RootDirectory) : base(serviceProvider, RootDirectory)
    {
    }

    public T LoadContentExclusive<T>(string AssetName)
    {
        return ReadAsset<T>(AssetName, null);
    }

    public void Unload(IDisposable ContentItem)
    {
        ContentItem.Dispose();
    }
}

দ্বিতীয় সমস্যাটি হ'ল কোন টাইলগুলি লোড এবং আনলোড করা যায় তা কীভাবে সিদ্ধান্ত নেওয়া যায়। নিম্নলিখিতগুলি এই সমস্যার সমাধান করবে:

public class Tile
{
    public int X;
    public int Y;
    public Texture2D Texture;
}

int playerTileX;
int playerTileY;
int width;
int height;

ExclusiveContentManager contentEx;
Tile[,] tiles;

void updateLoadedTiles()
{
    List<Tile> loaded = new List<Tile>();

    // Determine which tiles need to be loaded
    for (int x = playerTileX - 1; x <= playerTileX + 1; x++)
        for (int y = playerTileY - 1; y <= playerTileY; y++)
        {
            if (x < 0 || x > width - 1) continue;
            if (y < 0 || y > height - 1) continue;

            loaded.Add(tiles[x, y]);
        }

    // Load and unload as necessary
    for (int x = 0; x < width; x++)
        for (int y = 0; y < height; y++)
        {
            if (loaded.Contains(tiles[x, y]))
            {
                if (tiles[x, y].Texture == null)
                    loadTile(x, y);
            }
            else
            {
                if (tiles[x, y].Texture != null)
                    contentEx.Unload(tiles[x, y].Texture);
            }
        }
}

void loadTile(int x, int y)
{
    Texture2D tex = contentEx.LoadEx<Texture2D>("tile_" + x + "_" + y);
    tiles[x, y].Texture = tex;
}

চূড়ান্ত বিষয়টি হ'ল কখন কীভাবে লোড এবং আনলোড করা যায় তা ঠিক করবেন। এটি সম্ভবত সবচেয়ে সহজ অংশ। প্লেয়ারের পর্দার অবস্থান নির্ধারণ করার পরে এটি কেবল আপডেট () পদ্ধতিতে করা যেতে পারে:

int playerScreenX;
int playerScreenY;
int tileWidth;
int tileHeight;

protected override void Update(GameTime gameTime)
{
    // Code to update player position, etc...

    // Load/unload
    int newPlayerTileY = (int)((float)playerScreenX / (float)tileWidth);
    int newPlayerTileX = (int)((float)playerScreenY / (float)tileHeight);

    if (newPlayerTileX != playerTileX || newPlayerTileY != playerTileY)
        updateLoadedTiles();

    base.Update(gameTime);
}

অবশ্যই আপনারও টাইলস আঁকার দরকার, তবে টাইলউইথ, টাইলহাইট এবং টাইলস [] অ্যারে দেওয়া, এটি তুচ্ছ হওয়া উচিত।


ধন্যবাদ. খুব সুন্দর করে বললেন। আমি যদি একটি পরামর্শ দিতে চাই, যদি আপনি জানেন: আপনি কীভাবে টাইলগুলির লোড একটি থ্রেডে সম্পন্ন করবেন তা বর্ণনা করতে পারতেন। আমি কল্পনা করেছি যে একবারে 3 800x600 টাইল লোড করা সামান্য গেমটি বিরতি দেবে।
pek

টেক্সচার 2 ডি অবজেক্ট তৈরি করার সময় গ্রাফিক্স কার্ডটি জড়িত হওয়া দরকার, সুতরাং যতদূর আমি জানি এটি এখনও দ্বিতীয় থ্রেডে লোডিং করা হলেও এটি এড়িয়ে যেতে পারে।
শন জেমস

0

আপনি যা করতে চান তা বেশ সাধারণ। এটি এবং অন্যান্য সাধারণ কৌশলগুলির উপর একটি সুন্দর টিউটোরিয়ালের জন্য, এই টাইল ইঞ্জিন সিরিজটি দেখুন

আপনি যদি এর আগে কিছু না করেন তবে আমি সিরিজটি দেখার পরামর্শ দিই। তবে আপনি চাইলে আপনি শেষ টিউটোরিয়াল কোডটি পেতে পারেন। আপনি যদি পরে করেন তবে অঙ্কন পদ্ধতিটি দেখুন।

সংক্ষেপে, আপনাকে প্লেয়ারের চারপাশে আপনার নূন্যতম এবং সর্বাধিক এক্স / ওয়াই পয়েন্টগুলি সন্ধান করতে হবে। একবার আপনি একবারে প্রত্যেকটি লুপ করে সেই টাইলটি আঁকবেন।

public override void Draw(GameTime gameTime)
{
    Point min = currentMap.WorldPointToTileIndex(camera.Position);
    Point max = currentMap.WorldPointToTileIndex( camera.Position +
        new Vector2(
            ScreenManager.Viewport.Width + currentMap.TileWidth,
            ScreenManager.Viewport.Height + currentMap.TileHeight));


    min.X = (int)Math.Max(min.X, 0);
    min.Y = (int)Math.Max(min.Y, 0);
    max.X = (int)Math.Min(max.X, currentMap.Width);
    max.Y = (int)Math.Min(max.Y, currentMap.Height + 100);

    ScreenManager.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend
                                    , SpriteSortMode.Immediate
                                    , SaveStateMode.None
                                    , camera.TransformMatrix);
    for (int x = min.X; x < max.X; x++)
    {
        for (int y = min.Y; y < max.Y; y++)
        {

            Tile tile = Tiles[x, y];
            if (tile == null)
                continue;

            Rectangle currentPos = new Rectangle(x * currentMap.TileWidth, y * currentMap.TileHeight, currentMap.TileWidth, currentMap.TileHeight);
            ScreenManager.SpriteBatch.Draw(tile.Texture, currentPos, tile.Source, Color.White);
        }
    }

    ScreenManager.SpriteBatch.End();
    base.Draw(gameTime);
}

public Point WorldPointToTileIndex(Vector2 worldPoint)
{
    worldPoint.X = MathHelper.Clamp(worldPoint.X, 0, Width * TileWidth);
    worldPoint.Y = MathHelper.Clamp(worldPoint.Y, 0, Height * TileHeight);


    Point p = new Point();

    // simple conversion to tile indices
    p.X = (int)Math.Floor(worldPoint.X / TileWidth);
    p.Y = (int)Math.Floor(worldPoint.Y / TileWidth);

    return p;
}

আপনি দেখতে পাচ্ছেন অনেক কিছুই চলছে। আপনার এমন একটি ক্যামেরা দরকার যা আপনার ম্যাট্রিক্স তৈরি করতে চলেছে, আপনার বর্তমান পিক্সেল অবস্থানটি একটি টাইল সূচীতে রূপান্তর করতে হবে, আপনি আপনার ন্যূনতম / সর্বাধিক পয়েন্টগুলি খুঁজে পান (আমি আমার ম্যাক্সে কিছুটা যুক্ত করব যাতে এটি দৃশ্যমান পর্দার বাইরে কিছুটা আঁকবে) ), এবং তারপরে আপনি এটিকে আঁকতে পারেন।

আমি সত্যিই টিউটোরিয়াল সিরিজ দেখার পরামর্শ দিই। তিনি আপনার বর্তমান সমস্যা, কীভাবে টাইল সম্পাদক তৈরি করবেন, প্লেয়ারকে সীমানার মধ্যে রেখে, স্প্রিট অ্যানিমেশন, এআই মিথস্ক্রিয়া ইত্যাদি ...

সাইড নোটে টাইলডলিব এটি অন্তর্নির্মিত রয়েছে You আপনি তাদের কোডটিও অধ্যয়ন করতে পারেন।


যদিও এটি খুব সহায়ক, এটি কেবল টাইল মানচিত্রের উপস্থাপনাটি কভার করে। প্রাসঙ্গিক টাইলস লোড এবং আনলোড সম্পর্কে কী? আমি মেমরিতে 100 800x600 টাইল লোড করতে পারি না। আমি ভিডিও টিউটোরিয়ালগুলি একবার দেখে নেব; ধন্যবাদ।
pek

আহ .. আমি আপনার প্রশ্ন ভুল বুঝেছি। সুতরাং আপনি কি একটি traditionalতিহ্যবাহী টাইলম্যাপ ব্যবহার করছেন, বা আপনার স্তরটির জন্য কোনও বড় চিত্র রয়েছে যা আপনি টুকরো টুকরো করেছেন?

কেবল একটি চিন্তা .... আপনি আপনার টাইলসের নাম একটি অ্যারেতে সঞ্চয় করতে পারেন এবং কী লোড করতে হবে এবং আঁকতে হবে তা জানতে একই কৌশলটি ব্যবহার করতে পারেন। কোনও বস্তু পুনরায় ব্যবহার করার চেষ্টা করার কথা মনে রাখবেন বা আপনি প্রচুর আবর্জনা তৈরি করতে পারেন

দ্বিতীয়: মানচিত্রটি 800x600 পিক্সের 10x10 টাইলগুলিতে বিভক্ত 8000x6000। পুনঃব্যবহার হিসাবে, আমার কাছে ইতিমধ্যে একটি কন্টেন্ট ম্যানেজার রয়েছে যা এর জন্য দায়ী।
pek

0

আমি আমার বর্তমান প্রকল্পের জন্য খুব অনুরূপ কিছু নিয়ে কাজ করছি। কীভাবে নিজের উপর কিছুটা সহজ করে তুলতে হবে তার কয়েকটি পক্ষের নোট সহ আমি কীভাবে এটি করছি তা দ্রুত চালিয়ে যাওয়া।

আমার জন্য, প্রথম সমস্যাটি ছিল বিশ্বকে ছোট ছোট খণ্ডে ভাঙা যা ফ্লাইতে লোড এবং আনলোড করা উপযুক্ত হবে। আপনি যেহেতু একটি টাইল ভিত্তিক মানচিত্র ব্যবহার করছেন, সেই ধাপটি উল্লেখযোগ্যভাবে সহজ হয়ে যায়। স্তরের প্রতিটি 3 ডি অবজেক্টের অবস্থান বিবেচনা করার পরিবর্তে আপনি ইতিমধ্যে আপনার স্তরটি টাইলসে সুন্দরভাবে বিভক্ত করেছেন। এটি আপনাকে সহজেই X কে Y টাইল খণ্ডে বিভক্ত করতে এবং এগুলি লোড করতে দেয়।

আপনি হাতের পরিবর্তে স্বয়ংক্রিয়ভাবে এটি করতে চাইছেন। যেহেতু আপনি এক্সএনএ ব্যবহার করছেন, আপনার স্তরের সামগ্রীর জন্য কাস্টম রফতানিকারীর সাথে সামগ্রী পাইপলাইন ব্যবহার করার বিকল্প রয়েছে। যদি আপনি পুনরায় সংগ্রহ না করে রফতানি প্রক্রিয়া চালানোর কোনও উপায় সম্পর্কে অবগত না হন তবে আমি সততার সাথে এর বিরুদ্ধে সুপারিশ করব। সি ++ যতটা কম সংকলন করতে ধীরে ধীরে ধীরে ধীরে নয়, তবুও আপনি ভিজুয়াল স্টুডিওটি লোড করতে এবং প্রতিবার মানচিত্রে সামান্য পরিবর্তন করার পরে আপনার গেমটি পুনরায় সংকলন করতে চান না।

এখানে আরেকটি গুরুত্বপূর্ণ বিষয় হ'ল আপনার স্তরের খণ্ডগুলি যুক্ত ফাইলগুলির জন্য আপনি একটি ভাল নামকরণ কনভেনশন ব্যবহার করেছেন তা নিশ্চিত করা। আপনি জানতে চান যে আপনি কাঙ্ক সি সি লোড করতে বা আনলোড করতে চান এবং তারপরে রান টাইমে আপনাকে যে ফাইল নামটি লোড করতে হবে তা তৈরি করতে চান। অবশেষে, এমন কোনও ছোট্ট জিনিস চিন্তা করুন যা আপনাকে রাস্তায় নামতে সহায়তা করতে পারে। খণ্ড কত বড় তা আবার রফতানি করতে সক্ষম হতে পেরে সত্যই চমৎকার লাগল, এবং তারপরে তাত্ক্ষণিক পারফরম্যান্সের প্রভাবগুলি দেখুন।

রান সময়, এটি এখনও বেশ সোজা। অবিচ্ছিন্নভাবে খণ্ডগুলি লোড এবং আনলোড করার জন্য আপনাকে কিছু উপায়ের প্রয়োজন হবে তবে এটি আপনার খেলা বা ইঞ্জিন কীভাবে কাজ করে তার উপর নির্ভর করে। আপনার দ্বিতীয় চিত্রটি হুবহু সঠিক - আপনাকে কী খণ্ডগুলি বোঝা বা লোড করা উচিত তা নির্ধারণ করতে হবে এবং কেসটি ইতিমধ্যে যদি না হয় তবে তা করার জন্য উপযুক্ত অনুরোধ জানাতে হবে। আপনি একবারে কতগুলি অংশ বোঝা করেছেন তার উপর নির্ভর করে, যখনই প্লেয়ার একটি অংশ থেকে পরের অংশে একটি সীমানা অতিক্রম করে তখনই আপনি এটি করতে পারেন। সর্বোপরি, যে কোনও উপায়েই, আপনি নিশ্চিত করতে চান যে যথেষ্ট পরিমাণে লোড হয়েছে যে এমনকি খারাপ (যুক্তিসঙ্গত) লোড সময়কালে, খেলোয়াড় এটি দেখার আগেই খণ্ডটি এখনও লোড হয়। আপনি পারফরম্যান্স এবং মেমরির ব্যবহারের মধ্যে একটি ভাল ভারসাম্য না পাওয়া পর্যন্ত আপনি সম্ভবত এই সংখ্যাটি দিয়ে অনেক বেশি খেলতে চাইছেন।

প্রকৃত আর্কিটেকচার যতদূর যায়, আপনি আসলে কী লোড / আনলোড করা উচিত তা নির্ধারণের প্রক্রিয়া থেকে মেমরি থেকে ডেটা লোড এবং আনলোড করার প্রক্রিয়াটি বিমূর্ত করতে চান। আপনার প্রথম পুনরাবৃত্তির জন্য, আমি লোডিং / আনলোড লোড করার পারফরম্যান্স সম্পর্কেও চিন্তা করব না এবং সম্ভবত সবচেয়ে সহজ কাজটি করতে পারি যা সম্ভবত কাজ করতে পারে এবং আপনি উপযুক্ত সময়ে উপযুক্ত অনুরোধগুলি উত্পন্ন করছেন তা নিশ্চিত করে। এরপরে, আপনি কীভাবে আবর্জনা হ্রাস করতে লোড করবেন তা অনুকূলকরণের দিকে নজর দিতে পারেন।

আমি যে ইঞ্জিনটি ব্যবহার করছিলাম তার কারণে আমি প্রচুর অতিরিক্ত জটিলতার মধ্যে পড়েছিলাম, তবে এটি বাস্তবায়ন নির্দিষ্ট। আমি যা করেছি সে সম্পর্কে আপনার যদি কোনও প্রশ্ন থাকে তবে দয়া করে মন্তব্য করুন এবং আমি যা করতে পারি তার সাহায্য করব out


1
আপনি ভিজ্যুয়াল স্টুডিওর বাইরের সামগ্রী পাইপলাইন চালাতে মিসবিল্ড ব্যবহার করতে পারেন। দ্বিতীয় উইনফোর্ডস নমুনাটি আপনি আবৃত করেছেন: creators.xna.com/en-US/sample/winforms_series2
অ্যান্ড্রু রাসেল

@ এন্ড্রু !!!!! তোমাকে অনেক ধন্যবাদ!!! ঠিক ঠিক সেই কারণেই আমি সামগ্রীর পাইপলাইনটি পুরোপুরি ছেড়ে দিতে চলেছিলাম!
pek
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.