সময়.ডেলটাটাইম ব্যবহার সত্ত্বেও চলন ফ্রেম হার নির্ভর করে বলে মনে হয়


13

ইউনিটিতে গেম অবজেক্টটি সরানোর জন্য প্রয়োজনীয় অনুবাদটি গণনা করার জন্য আমার কাছে নিম্নলিখিত কোড রয়েছে, যা ডাকা হয় LateUpdate। আমি যা বুঝতে পারি তা থেকে, আমার ব্যবহারটি Time.deltaTimeচূড়ান্ত অনুবাদ ফ্রেম রেটকে স্বতন্ত্র করে CollisionDetection.Move()তুলতে হবে (দয়া করে নোট করুন কেবলমাত্র রেসকাস্টগুলি করা হচ্ছে)।

public IMovementModel Move(IMovementModel model) {    
    this.model = model;

    targetSpeed = (model.HorizontalInput + model.VerticalInput) * model.Speed;

    model.CurrentSpeed = accelerateSpeed(model.CurrentSpeed, targetSpeed,
        model.Accel);

    if (model.IsJumping) {
        model.AmountToMove = new Vector3(model.AmountToMove.x,
            model.AmountToMove.y);
    } else if (CollisionDetection.OnGround) {
        model.AmountToMove = new Vector3(model.AmountToMove.x, 0);
    }

    model.FlipAnim = flipAnimation(targetSpeed);
    // If we're ignoring gravity, then just use the vertical input.
    // if it's 0, then we'll just float.
    gravity = model.IgnoreGravity ? model.VerticalInput : 40f;

    model.AmountToMove = new Vector3(model.CurrentSpeed, model.AmountToMove.y - gravity * Time.deltaTime);

    model.FinalTransform =
        CollisionDetection.Move(model.AmountToMove * Time.deltaTime,
            model.BoxCollider.gameObject, model.IgnorePlayerLayer);
    // Prevent the entity from moving too fast on the y-axis.
    model.FinalTransform = new Vector3(model.FinalTransform.x,
        Mathf.Clamp(model.FinalTransform.y, -1.0f, 1.0f),
        model.FinalTransform.z);

    return model;
}

private float accelerateSpeed(float currSpeed, float target, float accel) {
    if (currSpeed == target) {
        return currSpeed;
    }
    // Must currSpeed be increased or decreased to get closer to target
    float dir = Mathf.Sign(target - currSpeed);
    currSpeed += accel * Time.deltaTime * dir;
    // If currSpeed has now passed Target then return Target, otherwise return currSpeed
    return (dir == Mathf.Sign(target - currSpeed)) ? currSpeed : target;
}

private void OnMovementCalculated(IMovementModel model) {
    transform.Translate(model.FinalTransform);
}

যদি আমি গেমের ফ্রেমরেট 60FPS এ লক করে রাখি তবে আমার বিষয়গুলি প্রত্যাশা অনুযায়ী সরে যায়। তবে, যদি আমি এটি আনলক করি ( Application.targetFrameRate = -1;), কিছু অবজেক্টগুলি খুব ধীর গতিতে চলে যাবে তখন 144hz মনিটরে 200FPS অর্জন করার সময় আমি আশা করব। এটি কেবল একক সংঘর্ষে ঘটবে বলে মনে হয়, ইউনিটির সম্পাদকের মধ্যে নয়।

সম্পাদকের মধ্যে অবজেক্টের চলাফেরার জিআইএফ, আনলক করা এফপিএস

http://gfycat.com/SmugAnnualFugu

স্ট্যান্ডেলোন বিল্ডের মধ্যে অবজেক্ট মুভমেন্টের জিআইএফ, আনলক করা এফপিএস

http://gfycat.com/OldAmpleJuliabutterfly


2
আপনার এই পড়া উচিত। সময় বকেটিং আপনি যা চান তা এবং স্থির সময় পদক্ষেপ! gafferongames.com/game-physics/fix-your-timestep
অ্যালান ওল্ফ

উত্তর:


30

আপডেটের পরিবর্তনের অ-রৈখিক হারের ক্ষতিপূরণ দিতে ব্যর্থ হলে ফ্রেম ভিত্তিক সিমুলেশনগুলি ত্রুটিগুলি অনুভব করে।

উদাহরণস্বরূপ শূন্যের অবস্থান এবং বেগের মানগুলির সাথে শুরু হওয়া কোনও বস্তুর বিবেচনা করুন যার একটির ধ্রুবক ত্বরণ হয়।

আমরা যদি এই আপডেট যুক্তি প্রয়োগ করি:

velocity += acceleration * elapsedTime
position += velocity * elapsedTime

আমরা এই ফলাফলগুলি বিভিন্ন ফ্রেমের হারের অধীনে আশা করতে পারি: এখানে চিত্র বর্ণনা লিখুন

চূড়ান্ত বেগের চিকিত্সা করার ফলে ত্রুটিটি ঘটেছিল যদিও এটি পুরো ফ্রেমের জন্য প্রয়োগ হয়েছিল। এটি একটি রাইট রিমন সামের অনুরূপ এবং ত্রুটির পরিমাণ ফ্রেমের হারের সাথে পরিবর্তিত হয় (একটি ভিন্ন ফাংশনে চিত্রিত):

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


ভাগ্যক্রমে কাইনেমেটিক্স আমাদের রৈখিক ত্বরণের ফলে সৃষ্ট বাস্তুচালিত সঠিকভাবে গণনা করতে দেয়:

d =  vᵢ*t + (a*t²)/2

where:
  d  = displacement
  v = initial velocity
  a  = acceleration
  t  = elapsed time

breakdown:
  vᵢ*t     = movement due to the initial velocity
  (a*t²)/2 = change in movement due to acceleration throughout the frame

সুতরাং আমরা যদি এই আপডেট যুক্তি প্রয়োগ করি:

position += (velocity * elapsedTime) + (acceleration * elapsedTime * elapsedTime / 2)
velocity += acceleration * elapsedTime

আমাদের নিম্নলিখিত ফলাফল থাকবে:

এখানে চিত্র বর্ণনা লিখুন


2
এটি দরকারী তথ্য, তবে এটি কীভাবে প্রশ্নযুক্ত কোডটিকে সম্বোধন করে? প্রথমত, ফ্রেমরেট বৃদ্ধি পাওয়ার সাথে সাথে ত্রুটিটি নাটকীয়ভাবে নীচে নেমে আসে, সুতরাং 60 এবং 200 fps এর মধ্যে পার্থক্য নগণ্য (8 fps বনাম অনন্ত ইতিমধ্যে মাত্র 12.5% ​​খুব বেশি)। দ্বিতীয়ত, একবার স্প্রাইট পুরো গতিতে চলে গেলে, সবচেয়ে বড় পার্থক্য হচ্ছে 0.5 ইউনিট এগিয়ে। এটি সংযুক্ত। জিআইএফএস-এ দেখানো মতো আসল হাঁটার গতিকে প্রভাবিত করা উচিত নয়। যখন তারা ঘুরিয়ে দেয়, ত্বরণটি আপাতদৃষ্টিতে তাত্ক্ষণিকভাবে দেখা যায় (সম্ভবত বেশ কয়েকটি ফ্রেম 60+ fps এ, তবে পুরো সেকেন্ডে নয়)।
মাইকেলএস

2
এটি তখন কোনও ইউনিটি বা কোড ইস্যু, কোনও গণিতের সমস্যা নয়। একটি দ্রুত স্প্রেডশীট বলেছে যে আমরা যদি 1 = vi, vi = 0, di = 0, vmax = 1 ব্যবহার করি তবে আমাদের d = 0.5 দিয়ে ভি = 3 টি টি = 1 টিতে আঘাত করা উচিত। এটি 5 টি ফ্রেমের উপরে (ডিটি = 0.2), ডি (টি = 1) = 0.6। 50 টিরও বেশি ফ্রেম (ডিটি = 0.02), ডি (টি = 1) = 0.51। 500 টিরও বেশি ফ্রেম (ডিটি = 0.002), ডি (টি = 1) = 0.501। সুতরাং 5 fps 20% উচ্চ, 50 fps 2% উচ্চ, এবং 500 fps 0.2% উচ্চ। সাধারণভাবে ত্রুটিটি 100 / fps শতাংশ খুব বেশি। 50 fps 500 fps থেকে প্রায় 1.8% বেশি। এবং এটি কেবল ত্বরণের সময়। একবার বেগ সর্বোচ্চে আঘাত করলে, শূন্যের পার্থক্য থাকা উচিত। A = 100 এবং vmax = 5 এর সাথে আরও কম পার্থক্য থাকা উচিত।
মাইকেলএস

2
প্রকৃতপক্ষে, আমি এগিয়ে গিয়েছিলাম এবং আপনার কোডটি একটি ভিবি নেট অ্যাপে (1/60 এবং 1/200 সিমুলেট করে) ব্যবহার করেছি এবং বাউন্স পেয়েছি : 5 ফ্রেম 626 (10.433) সেকেন্ড বনাম বাউন্স: 5 ফ্রেম 2081 এ ( 10.405) সেকেন্ড । 60 এফপিএসে 0.27% বেশি সময়।
মাইকেলএস

2
এটি আপনার "গতিময়" পদ্ধতি যা 10% পার্থক্য দেয়। Traditionalতিহ্যগত পদ্ধতির পার্থক্য হল 0.27% পার্থক্য। আপনি এগুলি কেবল ভুলভাবে লেবেল করেছেন। আমি মনে করি এটি কারণ কারণ যখন আপনি গতিবেগ সর্বাধিক হয় তখন আপনি ভুলভাবে ত্বরণ সহ অন্তর্ভুক্ত হন। উচ্চ ফ্রেমরেট ফ্রেম প্রতি কম ত্রুটি যুক্ত করে, তাই আরও সঠিক ফলাফল দিন। আপনি প্রয়োজন if(velocity==vmax||velocity==-vmax){acceleration=0}। তারপরে ত্রুটিটি যথেষ্ট পরিমাণে নেমে যায়, যদিও এটি নিখুঁত নয় কারণ ফ্রেমের ত্বরণের কোন অংশটি শেষ হয়েছিল তা আমরা ঠিক বুঝতে পারি না।
মাইকেলস

6

আপনি কোথায় থেকে আপনার পদক্ষেপটি কল করছেন তা নির্ভর করে। আপনি যদি এটিকে আপডেট থেকে কল করে থাকেন তবে আপনি সময়.ডেলটাটাইম দিয়ে স্কেল করলে আপনার চলাচল প্রকৃতপক্ষে স্বতন্ত্র হবে তবে আপনি যদি এটি ফিক্সডআপ্টেট থেকে কল করেন তবে আপনাকে টাইম.ফিক্সডডেটাটাইম দিয়ে স্কেল করতে হবে। আমি অনুমান করেছি যে আপনি ফিক্সডআপডেট থেকে আপনার পদক্ষেপটি কল করছেন, কিন্তু টাইম.ডেলটাটাইম দিয়ে স্কেলিংয়ের ফলে apparentক্যের স্থির পদক্ষেপটি মূল লুপের চেয়ে ধীর গতিতে কমলে আপাত গতি হ্রাস পেতে পারে যা আপনার স্ট্যান্ডেলোন বিল্ডে যা ঘটছে তা ঘটে is যখন স্থির পদক্ষেপটি ধীর হয় তখন ফিক্সডেল্টটাইম বড় হয়।


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