এক্সএনএ 2 ডি ক্যামেরা স্ক্রোলিং - কেন ম্যাট্রিক্স ট্রান্সফর্ম ব্যবহার করবেন?


18

আমি একটি পরীক্ষার গেমটি তৈরি করছি যেখানে আমি চাই স্তরটি ক্রমাগত স্ক্রোলিং হয়। এই প্রভাবটি তৈরি করতে আমি একটি ক্যামেরা ক্লাস প্রতিষ্ঠা করেছি যা কেবল একটি ভেক্টর 2 অবস্থান এবং একটি এনম দিকনির্দেশনা সঞ্চয় করে। এটিতে 'সরানোর' জন্য একটি সরকারী পদ্ধতি রয়েছে যা কেবলমাত্র একটি নির্দিষ্ট হারে অবস্থান পরিবর্তন করে। আমি অঙ্কন করার সময় আমার টাইলগুলির অ্যারেটি লুপ করে যখন এই অবস্থানটি ব্যবহার করি। এই সব কাজ করে।

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

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

ক্যামেরা:

 class Camera {

    // The position of the camera.
    public Vector2 Position {
        get { return mCameraPosition; }
        set { mCameraPosition = value; }
    }
    Vector2 mCameraPosition;

    public Vector2 Origin { get; set; }

    public float Zoom { get; set; }

    public float Rotation { get; set; }

    public ScrollDirection Direction { get; set; }

    private Vector2 mScrollSpeed = new Vector2(20, 18);

    public Camera() {
        Position = Vector2.Zero;
        Origin = Vector2.Zero;
        Zoom = 1;
        Rotation = 0;
    }


    public Matrix GetTransform() {
        return Matrix.CreateTranslation(new Vector3(mCameraPosition, 0.0f)) *
               Matrix.CreateRotationZ(Rotation) *
               Matrix.CreateScale(Zoom, Zoom, 1.0f) *
               Matrix.CreateTranslation(new Vector3(Origin, 0.0f));
    }




    public void MoveCamera(Level level) {
        if (Direction == ScrollDirection.Up)
        {
            mCameraPosition.Y = MathHelper.Clamp(mCameraPosition.Y - mScrollSpeed.Y, 0, (level.Height * Tile.Height - level.mViewport.Height));
        }
    }

স্তর:

 public void Update(GameTime gameTime, TouchCollection touchState) {

            Camera.MoveCamera(this);
 }


 public void Draw(SpriteBatch spriteBatch) {
        //spriteBatch.Begin();
        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null, mCamera.GetTransform());


        DrawTiles(spriteBatch);

        spriteBatch.End();
    }

গেম - মাত্র স্তরের মধ্যে ড্রকে কল করে:

  protected override void Draw(GameTime gameTime)  {
        mGraphics.GraphicsDevice.Clear(Color.Black);

        //mSpriteBatch.Begin();

        // Draw the level.
        mLevel.Draw(mSpriteBatch);

        //mSpriteBatch.End();

        base.Draw(gameTime);
    }

================================================== =============================== সম্পাদনা:

প্রথমত, এখন পর্যন্ত আপনার সহায়তার জন্য ক্র্যাফটওয়ার্কসকে ধন্যবাদ জানাই।

আমি পরামর্শ নিয়ে চারদিকে খেললাম। যখন আমি সমস্ত টাইল আঁকতাম, তখন 30 থেকে 15 টি ফ্রেঞ্চ ট্যাঙ্ক হয় - সম্ভবত স্তরগুলি বেশ বড়।

সুতরাং আমি যা করেছি তা হ'ল ম্যাট্রিক্স প্রয়োগ করা এবং আপডেটে সরানো (প্রস্তাবিত হিসাবে) তবে ড্রতে আমি টাইলগুলির মাধ্যমে লুপিংয়ের জন্য ক্যামেরার অবস্থানটি ব্যবহার করি (অর্থাত্ বামদিকে কাউন্টারের শুরু এবং ডান টাইলের শেষে)। এটি সব ভালভাবে কাজ করে এবং আমি এতে খুশি :-)

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


1
"আমার নতুন ইস্যুটি প্লেয়ারের মধ্যে রয়েছে I স্পষ্টতই আমি এখন স্তরটির পরিবর্তে ক্যামেরাটি চালিয়ে যাচ্ছি, প্লেয়ারটি অবস্থান স্থির থাকায় ক্যামেরের পিছনে চলে যায়" " কেবল এটি পড়ুন এবং আমি এতটাই বিভ্রান্ত হয়ে পড়েছি কেন পৃথিবীতে আপনি প্লেয়ারকে স্তরটির স্থানাঙ্ক ব্যবস্থার মধ্যে নিয়ে যাবেন না?
ক্লাসিকথান্ডার

উত্তর:


15

ক্যামেরা ম্যাট্রিক্স রূপান্তরগুলি সহজ

একটি বেসিক ক্যামেরা তৈরি করা সহজ। নীচে আপনি বেসিকগুলি দিয়ে শুরু করবেন। এটিকে ঘুরে বেড়ানো, ঘোরানো, উত্তর স্কেলিং। প্রতি 2 ডি স্প্রিট মুভিং করা খুব একটা সমস্যা নয় তবে আপনি যদি স্কেলিং বা রোটেশন উভয় ক্ষেত্রেই ফ্যাক্টর হন তবে স্বতন্ত্রভাবে প্রতিটি স্প্রাইটে প্রয়োগ করা সত্যিই শক্ত হয়ে যায়।

class Camera2D 
{
    public float Zoom { get; set; }
    public Vector2 Location { get; set; }
    public float Rotation { get; set;}

    private Rectangle Bounds { get; set; }

    private Matrix TransformMatrix
    { 
        get: {
            return 
                Matrix.CreateTranslation(new Vector3(-Location.X, -Location.Y, 0)) *
                Matrix.CreateRotationZ(Rotation) *
                Matrix.CreateScale(Zoom) *
                Matrix.CreateTranslation(new Vector3(Bounds.Width * 0.5f, Bounds.Height * 0.5f, 0));
        }
    };

    public Camera2D(Viewport viewport) 
    {
        Bounds = viewport.Bounds;
    }
}

সমন্বিত সিস্টেম সংজ্ঞাগুলির মধ্যে রূপান্তর করা এটি সত্যই সহজ করে তোলে

সহজভাবে পর্দা থেকে বিশ্বের মহাকাশে যেতে। এটি সাধারণত পৃথিবীতে মাউসের অবস্থান বাছাইয়ের জন্য ব্যবহৃত হয়।

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));

বিশ্ব থেকে স্ক্রিন স্পেসে যাওয়ার জন্য বিপরীতটি করুন।

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

সামান্য পড়াশুনা করা ছাড়া ম্যাট্রিক্স ব্যবহার করার জন্য আর কোনও অঙ্কন নেই।

দৃশ্যমান অঞ্চলটি পাওয়া সহজ

public Rectangle VisibleArea {
    get {
        var inverseViewMatrix = Matrix.Invert(View);
        var tl = Vector2.Transform(Vector2.Zero, inverseViewMatrix);
        var tr = Vector2.Transform(new Vector2(_screenSize.X, 0), inverseViewMatrix);
        var bl = Vector2.Transform(new Vector2(0, _screenSize.Y), inverseViewMatrix);
        var br = Vector2.Transform(_screenSize, inverseViewMatrix);
        var min = new Vector2(
            MathHelper.Min(tl.X, MathHelper.Min(tr.X, MathHelper.Min(bl.X, br.X))), 
            MathHelper.Min(tl.Y, MathHelper.Min(tr.Y, MathHelper.Min(bl.Y, br.Y))));
        var max = new Vector2(
            MathHelper.Max(tl.X, MathHelper.Max(tr.X, MathHelper.Max(bl.X, br.X))), 
            MathHelper.Max(tl.Y, MathHelper.Max(tr.Y, MathHelper.Max(bl.Y, br.Y))));
        return new Rectangle((int)min.X, (int)min.Y, (int)(max.X - min.X), (int)(max.Y - min.Y));
    }
}

আপনি কেবল ক্যামেরার কোণগুলিকে রূপান্তর করতে পারেন এবং বিশ্বের স্থানটিতে তাদের অবস্থান পেতে পারেন। সর্বনিম্ন x, y মানগুলি এবং আপনি দেখতে পারা যায় এমন জায়গার চারপাশে একটি আয়তক্ষেত্র পেতে পারেন। ড্র কলগুলি কুলিং এবং অনুকূলকরণের জন্য খুব দরকারী Very


1
ধন্যবাদ। মনোগেম.এক্সটেন্ডেড লাইব্রেরিতে একটি ক্যামেরা প্রয়োগ করার সময় আমি এই সহায়কটি পেয়েছি
ক্র্যাফটওয়ার্কস

6

আপনার স্প্রাইটব্যাচে একটি ম্যাট্রিক্স প্রয়োগ করা একবারে পুরো ড্র কলকে রূপান্তর করে। এর অর্থ আপনার অঙ্কিত টাইলস পদ্ধতিতে আপনার ক্যামেরাটি ব্যবহার করার দরকার নেই।

এটি এর মতো অনেক সহজ হয়ে উঠতে পারে:

    // Loop through the number of visible tiles.
    for (int y = 0; y <= tiles.GetUpperBound(1); y++) {
        for (int x = 0; x <= tiles.GetUpperBound(0); x++) {

                // If the tile is not an empty space.
                if (tiles[x, y].Texture != null) {
                     // Get the position of the visible tile within the viewport by multiplying the counters by the tile dimensions
                     // and subtracting the camera offset values incase the position of the camera means only part of a tile is visible.
                     Vector2 tilePosition = new Vector2(x * Tile.Width, y * Tile.Height);
                     // Draw the correct tile
                     spriteBatch.Draw(tiles[x, y].Texture, tilePosition, Color.White);
                }
        }
    }

সুতরাং একটি ম্যাট্রিক্স ব্যবহারের বিন্দুটি যাতে আপনাকে এটি সম্পর্কে চিন্তা করতে হবে না। কেবল জিনিসগুলি আঁকুন এবং ক্যামেরাটিকে স্বাধীনভাবে সরান।

এছাড়াও, আপনার মুভক্যামেরা পদ্ধতিটি কিছুটা অদ্ভুত দেখাচ্ছে। নির্ভরতা হিসাবে কোনও স্তরকে এমন ক্যামেরা শ্রেণি নেওয়া খুব অস্বাভাবিক। আরও একটি সাধারণ বাস্তবায়ন এর মতো দেখতে পাবেন:

public void MoveCamera(float deltaX, float deltaY) {
    mCameraPosition.X += deltaX;
    mCameraPosition.Y += deltaY;
}

তারপরে আপনার আপডেট পদ্ধতিতে আপনি এর মতো কিছু করতে পারেন:

    if (Direction == ScrollDirection.Up)
    {
        mCamera.MoveCamera(mScrollSpeed.Y, 0);
    }

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

সম্পাদনা: প্রশ্নের দ্বিতীয় অংশের জন্য।

যদিও এটি সত্য যে আপনি আপনার ব্যাচের গণনা কম রাখতে চান, 2 বা 3 থাকা মোটেও সমস্যা হওয়া উচিত নয়। সুতরাং আপনার কাছে যদি দ্বিতীয় স্প্রাইট ব্যাচ তৈরি করার উপযুক্ত কারণ থাকে তবে এটি করুন।

এটি বলেছিল, সম্ভবত এই ক্ষেত্রে দ্বিতীয় স্প্রাইট ব্যাচ ব্যবহার করার কোনও ভাল কারণ নেই। আরও সম্ভবত, আপনি একইভাবে স্প্রেট ব্যাচে ক্যামেরা ট্রান্সফর্ম প্রয়োগ করে টাইলস আঁকেন ঠিক একই পদ্ধতিতে আপনার প্লেয়ারটি আঁকতে চান।

আপনার কোড খেলোয়াড় কেন কিছু কোড না দেখে পিছিয়ে পড়ছেন তা বলা একটু কঠিন তবে আপনি যদি নিজের খেলোয়াড়কে টাইলের মতো ঠিক একই অবস্থানে আঁকেন তবে সে একই পজিশনে একই অবস্থানে উপস্থিত হবে এমন যুক্তিটি দাঁড় করানো একটু কঠিন but স্প্রাইট ব্যাচ

উদাহরণস্বরূপ, আপনি যদি খেলোয়াড়টি টাইল 10, 10 এ উপস্থিত হতে চান তবে আপনি এটি করতে পারেন:

var playerPosition = new Vector2(10 * Tile.Width, 10 * Tile.Height);
spriteBatch.Draw(player.Texture, playerPosition, Color.White);

জিনিসগুলি যেখানে রয়েছে সেগুলি আঁকানোর চিন্তাভাবনার মানসিকতায় Tryোকার চেষ্টা করুন এবং ক্যামেরা আক্ষরিক অর্থে পুরো "দৃশ্যের" দৃশ্যে চলে আসে। আপনার ম্যাট্রিক্স রূপান্তর এটিই করছে।


এটি সত্যিই সহায়ক এবং সাফ জিনিসগুলি বোঝা আপ! তথ্যের জন্য ধন্যবাদ; অনেক প্রশংসিত. আমি আজই আপনার পরামর্শটি বাস্তবায়নের চেষ্টা করব এবং আমি কীভাবে এগিয়ে যাব তা আপনাকে জানাব। আবার ধন্যবাদ.
পেকটাস এক্সাভ্যাটাম

এছাড়াও, কেবল আগ্রহের বাইরে, ভিউপোর্টে কেবল টাইলস আঁকতে ম্যাট্রিক্স রূপান্তরটি ব্যবহার করার কোনও উপায় আছে কি?
পেকটাস এক্সাভ্যাটাম

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

ঠিক আছে ধন্যবাদ. আমি এটির সাথে প্রায় খেলেছি এবং কোথাও পেয়েছি তবে খেলোয়াড়ের সাথে কী করা উচিত সে সম্পর্কে একটি প্রশ্নে ছুটে এসেছি - দয়া করে প্রশ্নের সম্পাদনাগুলি দেখুন।
পেকটাস এক্সাভ্যাটাম

ধন্যবাদ, আমি আপনার পরামর্শ নিয়েছি এবং একই স্প্রাইট ব্যাচ ব্যবহারের বিকল্পের সাথে চলেছি এবং আপডেটে ক্যামেরার অবস্থান পেয়েছি এবং অঙ্কনের সময় প্লেয়ারের পজিশনে এটি প্রয়োগ করি। ভাল কাজ মনে হচ্ছে। আপনার সমস্ত সহায়তার জন্য ধন্যবাদ, কিছু সময়ের জন্য ক্যামেরায় আটকে গেছি। এখন আরও পরিষ্কার :-)
প্যাক্টাস এক্সাভ্যাটাম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.