ADS

Mendesain Adegan Massa

 Mendesain Adegan Massa

Pada bagian ini, Anda akan membuat kode monster, yang akan kita sebut sebagai gerombolan. Pada pelajaran berikutnya, kita akan memunculkan mereka secara acak di sekitar area yang dapat dimainkan.

Mari kita rancang monster itu sendiri dalam adegan baru. Struktur simpulnya akan mirip dengan adegannya player.tscn.

Buat adegan dengan, sekali lagi, simpul CharacterBody3D sebagai akarnya. Beri nama Mob. Tambahkan simpul anak Node3D , beri nama Pivot. Lalu seret dan jatuhkan berkas mob.glbdari dok FileSystem ke Pivotuntuk menambahkan model 3D monster ke adegan.

../../_images/drag_drop_mob.webp

Anda dapat mengganti nama mobnode yang baru dibuat menjadi Character.

gambar0

Kita memerlukan bentuk tabrakan agar badan kita dapat berfungsi. Klik kanan pada Mobsimpul, akar adegan, dan klik Tambahkan Simpul Anak .

gambar1

Tambahkan CollisionShape3D .

gambar2

Di Inspektur , tetapkan BoxShape3D ke properti Bentuk .

../../_images/08.create_box_shape3D.jpg

Kita harus mengubah ukurannya agar lebih sesuai dengan model 3D. Anda dapat melakukannya secara interaktif dengan mengeklik dan menyeret titik oranye.

Kotak tersebut harus menyentuh lantai dan sedikit lebih tipis dari modelnya. Mesin fisika bekerja sedemikian rupa sehingga jika bola pemain menyentuh sudut kotak, tabrakan akan terjadi. Jika kotak tersebut sedikit terlalu besar dibandingkan dengan model 3D, Anda mungkin mati jauh dari monster tersebut, dan permainan akan terasa tidak adil bagi para pemain.

gambar4

Perhatikan bahwa kotak saya lebih tinggi daripada monster. Hal ini tidak masalah dalam permainan ini karena kita melihat pemandangan dari atas dan menggunakan perspektif tetap. Bentuk tabrakan tidak harus sama persis dengan model. Cara permainan terasa saat Anda mengujinya yang akan menentukan bentuk dan ukurannya.

Menghapus monster dari layar

Kita akan memunculkan monster pada interval waktu yang teratur di level permainan. Jika kita tidak hati-hati, jumlah mereka dapat meningkat hingga tak terbatas, dan kita tidak menginginkan itu. Setiap contoh monster memiliki memori dan biaya pemrosesan, dan kita tidak ingin membayarnya saat monster berada di luar layar.

Setelah monster meninggalkan layar, kita tidak membutuhkannya lagi, jadi kita harus menghapusnya. Godot memiliki node yang mendeteksi saat objek meninggalkan layar, VisibleOnScreenNotifier3D , dan kita akan menggunakannya untuk menghancurkan monster kita.

Catatan

Bila Anda terus-menerus membuat instance suatu objek, ada teknik yang dapat Anda gunakan untuk menghindari biaya pembuatan dan penghancuran instance sepanjang waktu yang disebut pooling. Teknik ini terdiri dari pembuatan awal array objek dan penggunaan ulang objek tersebut berulang kali.

Saat bekerja dengan GDScript, Anda tidak perlu khawatir tentang hal ini. Alasan utama untuk menggunakan pool adalah untuk menghindari pembekuan dengan bahasa yang dikumpulkan dari sampah seperti C# atau Lua. GDScript menggunakan teknik yang berbeda untuk mengelola memori, penghitungan referensi, yang tidak memiliki peringatan tersebut. Anda dapat mempelajari lebih lanjut tentang hal itu di sini: Manajemen memori .

Pilih Mobsimpul dan tambahkan simpul anak VisibleOnScreenNotifier3D . Kotak lain, kali ini berwarna merah muda, akan muncul. Saat kotak ini sepenuhnya meninggalkan layar, simpul akan memancarkan sinyal.

gambar5

Ubah ukurannya menggunakan titik oranye hingga menutupi seluruh model 3D.

gambar6

Mengkodekan pergerakan massa

Mari kita terapkan gerakan monster. Kita akan melakukannya dalam dua langkah. Pertama, kita akan menulis skrip yang Mobmendefinisikan fungsi untuk menginisialisasi monster. Kemudian kita akan membuat kode mekanisme spawn acak dalam main.tscnadegan dan memanggil fungsi dari sana.

Lampirkan skrip ke Mob.

gambar7

Berikut kode gerakan untuk memulai. Kami mendefinisikan dua properti, min_speed dan max_speed, untuk mendefinisikan rentang kecepatan acak, yang nantinya akan kami gunakan untuk mendefinisikan CharacterBody3D.velocity.

extends CharacterBody3D

# Minimum speed of the mob in meters per second.
@export var min_speed = 10
# Maximum speed of the mob in meters per second.
@export var max_speed = 18

func _physics_process(_delta):
move_and_slide()

using Godot;

public partial class Mob : CharacterBody3D
{
    // Don't forget to rebuild the project so the editor knows about the new export variable.

    // Minimum speed of the mob in meters per second
    [Export]
    public int MinSpeed { get; set; } = 10;
    // Maximum speed of the mob in meters per second
    [Export]
    public int MaxSpeed { get; set; } = 18;

    public override void _PhysicsProcess(double delta)
    {
        MoveAndSlide();
    }
}

Mirip dengan pemain, kita menggerakkan monster setiap frame dengan memanggil fungsi CharacterBody3D.move_and_slide(). Kali ini, kita tidak memperbarui velocitysetiap frame; kita ingin monster bergerak dengan kecepatan konstan dan meninggalkan layar, bahkan jika menabrak rintangan.

Kita perlu mendefinisikan fungsi lain untuk menghitung CharacterBody3D.velocity. Fungsi ini akan mengarahkan monster ke arah pemain dan mengacak sudut gerak dan kecepatannya.

Fungsi ini akan mengambil start_position, posisi munculnya massa, dan player_positionsebagai argumennya.

Kami memposisikan massa di start_positiondan memutarnya ke arah pemain menggunakan look_at_from_position()metode, dan mengacak sudut dengan memutar jumlah acak di sekitar sumbu Y. Di bawah ini, randf_range()menghasilkan nilai acak antara radian dan radian.-PI / 4PI / 4

# This function will be called from the Main scene.
func initialize(start_position, player_position):
# We position the mob by placing it at start_position
# and rotate it towards player_position, so it looks at the player.
look_at_from_position(start_position, player_position, Vector3.UP)
# Rotate this mob randomly within range of -45 and +45 degrees,
# so that it doesn't move directly towards the player.
rotate_y(randf_range(-PI / 4, PI / 4))

// This function will be called from the Main scene.
public void Initialize(Vector3 startPosition, Vector3 playerPosition)
{
    // We position the mob by placing it at startPosition
    // and rotate it towards playerPosition, so it looks at the player.
    LookAtFromPosition(startPosition, playerPosition, Vector3.Up);
    // Rotate this mob randomly within range of -45 and +45 degrees,
    // so that it doesn't move directly towards the player.
    RotateY((float)GD.RandRange(-Mathf.Pi / 4.0, Mathf.Pi / 4.0));
}

Kita mendapat posisi acak, sekarang kita butuh random_speedrandi_range()akan berguna karena memberikan nilai int acak, dan kita akan menggunakan min_speeddan max_speedrandom_speedhanyalah bilangan bulat, dan kita hanya menggunakannya untuk mengalikan CharacterBody3D.velocity. Setelah random_speedditerapkan, kita memutar CharacterBody3D.velocityVector3 ke arah pemain.

func initialize(start_position, player_position):
# ...

# We calculate a random speed (integer)
var random_speed = randi_range(min_speed, max_speed)
# We calculate a forward velocity that represents the speed.
velocity = Vector3.FORWARD * random_speed
# We then rotate the velocity vector based on the mob's Y rotation
# in order to move in the direction the mob is looking.
velocity = velocity.rotated(Vector3.UP, rotation.y)

public void Initialize(Vector3 startPosition, Vector3 playerPosition)
{
    // ...

    // We calculate a random speed (integer).
    int randomSpeed = GD.RandRange(MinSpeed, MaxSpeed);
    // We calculate a forward velocity that represents the speed.
    Velocity = Vector3.Forward * randomSpeed;
    // We then rotate the velocity vector based on the mob's Y rotation
    // in order to move in the direction the mob is looking.
    Velocity = Velocity.Rotated(Vector3.Up, Rotation.Y);
}

Meninggalkan layar

Kita masih harus menghancurkan gerombolan saat mereka meninggalkan layar. Untuk melakukannya, kita akan menghubungkan sinyal simpul VisibleOnScreenNotifier3Dscreen_exited kita ke Mob.

Kembali ke viewport 3D dengan mengeklik label 3D di bagian atas editor. Anda juga dapat menekan di macOS).Ctrl + F2Opt + 2

gambar8

Pilih node VisibleOnScreenNotifier3D dan di sisi kanan antarmuka, navigasikan ke Node dock. Klik dua kali pada screen_exited()sinyal.

gambar9

Hubungkan sinyal keMob

gambar10

Ini akan menambahkan fungsi baru untuk Anda dalam skrip mob Anda, _on_visible_on_screen_notifier_3d_screen_exited(). Dari situ, panggil queue_free() metode tersebut. Fungsi ini menghancurkan instance yang dipanggilnya.

func _on_visible_on_screen_notifier_3d_screen_exited():
queue_free()

// We also specified this function name in PascalCase in the editor's connection window.
private void OnVisibilityNotifierScreenExited()
{
    QueueFree();
}

Monster kita siap memasuki permainan! Di bagian selanjutnya, Anda akan memunculkan monster di level permainan.

Berikut ini mob.gdnaskah lengkapnya untuk referensi.

extends CharacterBody3D

# Minimum speed of the mob in meters per second.
@export var min_speed = 10
# Maximum speed of the mob in meters per second.
@export var max_speed = 18

func _physics_process(_delta):
move_and_slide()

# This function will be called from the Main scene.
func initialize(start_position, player_position):
# We position the mob by placing it at start_position
# and rotate it towards player_position, so it looks at the player.
look_at_from_position(start_position, player_position, Vector3.UP)
# Rotate this mob randomly within range of -45 and +45 degrees,
# so that it doesn't move directly towards the player.
rotate_y(randf_range(-PI / 4, PI / 4))

# We calculate a random speed (integer)
var random_speed = randi_range(min_speed, max_speed)
# We calculate a forward velocity that represents the speed.
velocity = Vector3.FORWARD * random_speed
# We then rotate the velocity vector based on the mob's Y rotation
# in order to move in the direction the mob is looking.
velocity = velocity.rotated(Vector3.UP, rotation.y)

func _on_visible_on_screen_notifier_3d_screen_exited():
queue_free()
using Godot;

public partial class Mob : CharacterBody3D
{
    // Minimum speed of the mob in meters per second.
    [Export]
    public int MinSpeed { get; set; } = 10;
    // Maximum speed of the mob in meters per second.
    [Export]
    public int MaxSpeed { get; set; } = 18;

    public override void _PhysicsProcess(double delta)
    {
        MoveAndSlide();
    }

    // This function will be called from the Main scene.
    public void Initialize(Vector3 startPosition, Vector3 playerPosition)
    {
        // We position the mob by placing it at startPosition
        // and rotate it towards playerPosition, so it looks at the player.
        LookAtFromPosition(startPosition, playerPosition, Vector3.Up);
        // Rotate this mob randomly within range of -45 and +45 degrees,
        // so that it doesn't move directly towards the player.
        RotateY((float)GD.RandRange(-Mathf.Pi / 4.0, Mathf.Pi / 4.0));

        // We calculate a random speed (integer).
        int randomSpeed = GD.RandRange(MinSpeed, MaxSpeed);
        // We calculate a forward velocity that represents the speed.
        Velocity = Vector3.Forward * randomSpeed;
        // We then rotate the velocity vector based on the mob's Y rotation
        // in order to move in the direction the mob is looking.
        Velocity = Velocity.Rotated(Vector3.Up, Rotation.Y);
    }

    // We also specified this function name in PascalCase in the editor's connection window.
    private void OnVisibilityNotifierScreenExited()
    {
        QueueFree();
    }
}


Tidak ada komentar:

Posting Komentar