Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Mekanika Pengguna Platform: Platform Bergerak

Scroll to top
Read Time: 8 min

() translation by (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Dalam tutorial ini Anda akan belajar bagaimana membuat platform yang bergerak dan memastikan bahwa objek yang dikendarai akan mempertahankan posisi relatif mereka. Kami juga akan menangani kasus yang telah dipilah antara platform dan dasarnya.

Prasyarat

Tutorial ini didasarkan pada seri Basic Platformer Physics. Secara khusus, kami akan menggunakan kode berdasarkan bagian 8 tutorial sebagai titik awal, dengan beberapa modifikasi.  Simak tutorial series, dan khususnya the last part. Prinsip di balik penerapannya akan tetap ada meski anda menggunakan solusi fisika yang berbeda, namun kodenya akan kompatibel dengan versi yang disajikan dalam rangkaian tutorial.

Demo

Anda bisa mendownload demo dari tutorial attachments. Gunakan kunci WASD untuk memindahkan karakter, Space untuk menelurkan karakter kloning, dan P untuk menelurkan sebuah platform yang bergerak.  Tombol kursor sebelah kanan menciptakan ubin. Anda dapat menggunakan roda gulir atau tombol panah untuk memilih ubin yang ingin Anda tempatkan. Slider mengubah ukuran karakter pemain.

Demo tersebut telah dipublikasikan di Unity 2017.2b4, dan kode sumbernya juga kompatibel dengan versi Unity ini.

Pelaksanaan

Pindah Platform

Pertama-tama, mari membuat naskah untuk platform yang bergerak.

Inisialisasi

Mari kita mulai dengan membuat kelas objek.

1
public class MovingPlatform : MovingObject
2
{
3
}

Sekarang mari kita inisialisasi beberapa parameter dasar objek dalam fungsi init.

1
public void Init()
2
{
3
    mAABB.HalfSize = new Vector2(32.0f, 8.0f);
4
    mSlopeWallHeight = 0;
5
    mMovingSpeed = 100.0f;
6
    mIsKinematic = true;
7
    mSpeed.x = mMovingSpeed;
8
}

Kita mengatur ukuran dan kecepatan, dan kita membuat collider kinematic, yang berarti tidak akan dipindahkan oleh objek biasa. Kami juga mengatur mSlopeWallHeight ke 0, yang berarti bahwa platform tidak akan mendaki lereng-itu akan selalu memperlakukan mereka sebagai dinding.

Tingkah laku

Perilaku untuk platform bergerak khusus ini akan menjadi seperti ini: gerakan awal benar, dan setiap kali anda menemui hambatan, ubah arah 90 derajat searah jarum jam.

1
public void CustomUpdate()
2
{
3
    if (mPS.pushesRightTile && !mPS.pushesBottomTile)
4
        mSpeed.y = -mMovingSpeed;
5
    else if (mPS.pushesBottomTile && !mPS.pushesLeftTile)
6
        mSpeed.x = -mMovingSpeed;
7
    else if (mPS.pushesLeftTile && !mPS.pushesTopTile)
8
        mSpeed.y = mMovingSpeed;
9
    else if (mPS.pushesTopTile && !mPS.pushesRightTile)
10
        mSpeed.x = mMovingSpeed;
11
    
12
    UpdatePhysics();
13
}

Inilah pola yang divisualisasikan:

The pattern visualizedThe pattern visualizedThe pattern visualized

Menempelkan Karakter ke Platform

Saat ini, jika karakter berdiri di atas platform, platform hanya akan meluncur dari bawahnya, seolah-olah tidak ada gesekan antara benda-benda itu. Kami akan mencoba untuk memperbaiki itu, dengan menyalin offset platform.

The offset of the platformThe offset of the platformThe offset of the platform

Menentukan Objek Induknya

Pertama-tama, kami ingin menyadari akan objek tersebut, jikapun ada, karakter kami akan sangat nampak. Mari menyatakan referensi ke MovingObject .

1
public MovingObject mMountParent = null;

Sekarang, UpdatePhysicsResponse, Apabila kita menemukan bahwa kita bertabrakan dengan objek dibawah kita, kita bisa menugaskan referensi ini. Mari buat fungsi yang menugaskan referensi terlebih dahulu.

1
public void TryAutoMount(MovingObject platform)
2
{
3
    if (mMountParent == null)
4
    {
5
        mMountParent = platform;
6
    }
7
}

Sekarang mari kita gunakan tempat yang tepat, mari katakana saja bahwa objek kita bertabrakan dengan objek lain di bawahnya. 

1
else if (overlap.y == 0.0f)
2
{
3
    if (other.mAABB.Center.y > mAABB.Center.y)
4
    {
5
        mPS.pushesTopObject = true;
6
        mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);
7
    }
8
    else
9
    {
10
        TryAutoMount(other);
11
        mPS.pushesBottomObject = true;
12
        mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);
13
    }
14
    continue;
15
}

Tempat pertama adalah saat kita memeriksa apakah benda-benda itu menyentuh. 

1
if (overlap.y < 0.0f)
2
{
3
    mPS.pushesTopObject = true;
4
    mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);
5
}
6
else
7
{
8
    TryAutoMount(other);
9
    mPS.pushesBottomObject = true;
10
    mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);
11
}

Tempat kedua adalah saat mereka tumpang tindih.

Sekarang kita sudah membuatnya tertutup, mari kita tangani pergerakan dari objek kita. Mari kita ubah fungsi UpdatePhysics dari tutorial sebelumnya.

Mari kita nyatakan variabel kelas untuk offset yang kita butuhkan untuk memindahkan karakter kita.

1
public Vector2 mOffset;

Sekarang mari kita menggantikan offset lokal tua dengan kelas satu.

1
mOffset = mSpeed * Time.deltaTime;

Dalam kasus objek pada platform, mari kita menambahkan gerakan platform untuk offset.

1
mOffset = mSpeed * Time.deltaTime;
2
3
if (mMountParent != null)
4
{
5
    if (HasCollisionDataFor(mMountParent))
6
        mOffset += mMountParent.mPosition - mMountParent.mOldPosition;
7
    else
8
        mMountParent = null;
9
}

Perhatikan bahwa kami juga memeriksa di sini apabila kami masih berhubungan dengan objek. Jika bukan itu masalahnya, maka kita tetapkan mMountParent menjadi null, untuk menandai bahwa objek ini tidak lagi dikendarai dengan yang lain.

Selanjutnya, mari kita pindahkan posisi objek kita dengan offset itu. Kami tidak akan menggunakan fungsi Move kami, tapi cukup ubah posisi.  Jadi dalam tabrakan cek antar benda, yang terjadi tepat setelah UpdatePhysics, kita akan mendapatkan hasilnya untuk posisi di frame ini daripada yang sebelumnya.

1
mOffset = mSpeed * Time.deltaTime;
2
3
if (mMountParent != null)
4
{
5
    if (HasCollisionDataFor(mMountParent))
6
        mOffset += mMountParent.mPosition - mMountParent.mOldPosition;
7
    else
8
        mMountParent = null;
9
}
10
11
mPosition += RoundVector(mOffset + mReminder);
12
mAABB.Center = mPosition;

Sekarang mari kita pindah ke UpdatePhysicsP2, yang disebut setelah tabrakan antara objek telah teratasi. Di sini kita membatalkan gerakan kita sebelumnya, yang belum diperiksa apakah itu benar atau tidak.

1
public void UpdatePhysicsP2()
2
    {
3
        mPosition -= RoundVector(mOffset + mReminder);
4
        mAABB.Center = mPosition;

Selanjutnya, kita lanjutkan ke UpdatePhysicsResponse untuk menerapkan perpindahan dari tumpang tindih dengan objek lain. Di sini, sebelumnya kami memodifikasi posisi secara langsung, tapi sekarang malah mari kita modifikasi mOffset, jadi perubahan posisi ini akan teratasi nanti saat kita menggunakan fungsi Move kita.

1
if (smallestOverlap == Mathf.Abs(overlap.x))
2
{
3
    float offsetX = overlap.x * speedRatioX;
4
5
    mOffset.x += offsetX;
6
    offsetSum.x += offsetX;
7
8
    if (overlap.x < 0.0f)
9
    {
10
        mPS.pushesRightObject = true;
11
        mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);
12
    }
13
    else
14
    {
15
        mPS.pushesLeftObject = true;
16
        mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);
17
    }
18
}
19
else
20
{
21
    float offsetY = overlap.y * speedRatioY;
22
23
    mOffset.y += offsetY;
24
    offsetSum.y += offsetY;
25
26
    if (overlap.y < 0.0f)
27
    {
28
        mPS.pushesTopObject = true;
29
        mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);
30
    }
31
    else
32
    {
33
        TryAutoMount(other);
34
        mPS.pushesBottomObject = true;
35
        mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);
36
    }
37
}

Sekarang kita bisa kembali ke UpdatePhysicsP2, di mana kita hanya memanggil UpdatePhysicsResponse dan Movefunctions seperti yang kita lakukan sebelumnya, untuk mendapatkan status posisi yang benar.

1
mPosition -= RoundVector(mOffset + mReminder);
2
mAABB.Center = mPosition;
3
4
UpdatePhysicsResponse();
5
6
if (mOffset != Vector2.zero)
7
    Move(mOffset, mSpeed, ref mPosition, ref mReminder, mAABB, ref mPS);

Perbaiki Pesanan Pembaruan

Karena cara kita memesan physics update, jika objek anak diperbarui sebelum orang tua, anak akan terus kehilangan kontak dengan platform saat bepergian naik / turun.

Traveling up or downTraveling up or downTraveling up or down

Untuk memperbaikinya, kapan pun kita mengatur mMountParent, jika platform berada di belakang anak dalam antrian update, kita bertukar keduanya, jadi objek induk selalu update terlebih dahulu. Mari kita lakukan modifikasi itu di TryAutoMountfunction.

1
public void TryAutoMount(MovingObject platform)
2
{
3
    if (mMountParent == null)
4
    {
5
        mMountParent = platform;
6
        if (platform.mUpdateId > mUpdateId)
7
            mGame.SwapUpdateIds(this, platform);
8
    }
9
}

Seperti yang dapat anda lihat, jika id update objek platform lebih besar daripada anak, urutan update objek akan ditukar, menghapus masalahnya.

The order of the objectsThe order of the objectsThe order of the objects

Itu cukup banyak ketika harus menempelkan karakter ke platform yang bergerak.

Deteksi Menjadi Hancur

Mendeteksi yang hancur sangat sederhana. Dalam UpdatePhysicsResponse, kita perlu melihat apakah tumpang tindih terhadap objek kinematik menggerakkan kita ke dinding.

Mari kita jaga sumbu X dulu:

1
if (smallestOverlap == Mathf.Abs(overlap.x))
2
{
3
    float offsetX = overlap.x * speedRatioX;
4
5
    mOffset.x += offsetX;
6
    offsetSum.x += offsetX;
7
8
    if (overlap.x < 0.0f)
9
    {
10
        mPS.pushesRightObject = true;
11
        mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);
12
    }
13
    else
14
    {
15
        mPS.pushesLeftObject = true;
16
        mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);
17
    }
18
}

Jika benda itu ada di sisi kanan kita dan kita sudah menekan dinding kiri, maka kita sebut Crushfunction, yang akan kita implementasikan nanti. Lakukan hal yang sama untuk sisi yang lain.

1
if (overlap.x < 0.0f)
2
{
3
    if (other.mIsKinematic && mPS.pushesLeftTile)
4
        Crush();
5
6
    mPS.pushesRightObject = true;
7
    mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);
8
}
9
else
10
{
11
    if (other.mIsKinematic && mPS.pushesRightTile)
12
        Crush();
13
14
    mPS.pushesLeftObject = true;
15
    mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);
16
}

Mari ulangi untuk sumbu Y.

1
if (overlap.y < 0.0f)
2
{
3
    if (other.mIsKinematic && mPS.pushesBottomTile)
4
        Crush();
5
6
    mPS.pushesTopObject = true;
7
    mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);
8
}
9
else
10
{
11
    if (other.mIsKinematic && mPS.pushesTopTile)
12
        Crush();
13
14
    TryAutoMount(other);
15
    mPS.pushesBottomObject = true;
16
    mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);
17
}

Fungsi Crush hanya akan memindahkan karakter ke pusat peta untuk demo.

1
public void Crush()
2
{
3
    mPosition = mMap.mPosition + new Vector3(mMap.mWidth / 2 * Map.cTileSize, mMap.mHeight / 2 * Map.cTileSize);
4
}

Hasilnya adalah karakter yang diteleport saat sedang dihancurkan oleh sebuah platform.

Being crushed by a platformBeing crushed by a platformBeing crushed by a platform

Kesimpulan

Ini adalah tutorial singkat karena menambahkan platform bergerak bukanlah tantangan besar, apalagi jika Anda mengenal sistem fisika dengan baik. Meminjam semua kode dalam rangkaian tutorial fisika, sebenarnya prosesnya sangat mulus.

Tutorial ini telah diminta beberapa kali, jadi saya harap anda merasa bahwa ini berguna! Terima kasih telah membaca, dan sampai bertemu dengan anda lain kali!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.