ADS

Memindahkan Pemain dengan Kode

 

Memindahkan Pemain Dengan Kode

Saatnya membuat kode! Kita akan menggunakan tindakan input yang kita buat di bagian terakhir untuk menggerakkan karakter.

Catatan

Untuk proyek ini, kami akan mengikuti konvensi penamaan Godot.

  • GDScript : Kelas (node) menggunakan PascalCase, variabel dan fungsi menggunakan snake_case, dan konstanta menggunakan ALL_CAPS (Lihat panduan gaya GDScript ).

  • C# : Kelas, variabel ekspor, dan metode menggunakan PascalCase, kolom privat menggunakan _camelCase, variabel dan parameter lokal menggunakan camelCase (Lihat panduan gaya C# ). Berhati-hatilah untuk mengetik nama metode dengan tepat saat menghubungkan sinyal.

Klik kanan Playernode dan pilih Lampirkan Skrip untuk menambahkan skrip baru ke dalamnya. Di jendela pop-up, atur Templat ke Kosong sebelum menekan tombol Buat . Kami mengaturnya ke Kosong karena kami ingin menulis kode kami sendiri untuk pergerakan pemain.

gambar0

Mari kita mulai dengan properti kelas. Kita akan menentukan kecepatan gerakan, percepatan jatuh yang mewakili gravitasi, dan kecepatan yang akan kita gunakan untuk menggerakkan karakter.

extends CharacterBody3D

# How fast the player moves in meters per second.
@export var speed = 14
# The downward acceleration when in the air, in meters per second squared.
@export var fall_acceleration = 75

var target_velocity = Vector3.ZERO

using Godot;

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

    // How fast the player moves in meters per second.
    [Export]
    public int Speed { get; set; } = 14;
    // The downward acceleration when in the air, in meters per second squared.
    [Export]
    public int FallAcceleration { get; set; } = 75;

    private Vector3 _targetVelocity = Vector3.Zero;
}

Ini adalah properti umum untuk benda yang bergerak. Ini target_velocityadalah vektor 3D yang menggabungkan kecepatan dengan arah. Di sini, kami mendefinisikannya sebagai properti karena kami ingin memperbarui dan menggunakan kembali nilainya di seluruh bingkai.

Catatan

Nilainya sangat berbeda dari kode 2D karena jaraknya dalam satuan meter. Sementara dalam 2D, seribu unit (piksel) mungkin hanya sesuai dengan setengah lebar layar Anda, dalam 3D, jaraknya adalah satu kilometer.

Mari kita buat kode gerakannya. Kita mulai dengan menghitung vektor arah input menggunakan Inputobjek global, dalam _physics_process().

func _physics_process(delta):
# We create a local variable to store the input direction.
var direction = Vector3.ZERO

# We check for each move input and update the direction accordingly.
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_back"):
# Notice how we are working with the vector's x and z axes.
# In 3D, the XZ plane is the ground plane.
direction.z += 1
if Input.is_action_pressed("move_forward"):
direction.z -= 1

public override void _PhysicsProcess(double delta)
{
    // We create a local variable to store the input direction.
    var direction = Vector3.Zero;

    // We check for each move input and update the direction accordingly.
    if (Input.IsActionPressed("move_right"))
    {
        direction.X += 1.0f;
    }
    if (Input.IsActionPressed("move_left"))
    {
        direction.X -= 1.0f;
    }
    if (Input.IsActionPressed("move_back"))
    {
        // Notice how we are working with the vector's X and Z axes.
        // In 3D, the XZ plane is the ground plane.
        direction.Z += 1.0f;
    }
    if (Input.IsActionPressed("move_forward"))
    {
        direction.Z -= 1.0f;
    }
}

Di sini, kita akan membuat semua perhitungan menggunakan _physics_process() fungsi virtual. Seperti _process(), fungsi ini memungkinkan Anda memperbarui node setiap frame, tetapi fungsi ini dirancang khusus untuk kode yang berhubungan dengan fisika seperti menggerakkan benda kinematik atau kaku.

Lihat juga

Untuk mempelajari lebih lanjut tentang perbedaan antara _process()dan _physics_process(), lihat Pemrosesan Idle dan Fisika .

Kita mulai dengan menginisialisasi directionvariabel ke Vector3.ZERO. Kemudian, kita periksa apakah pemain menekan satu atau beberapa input move_*dan perbarui vektor xdan zkomponennya sesuai dengan itu. Ini sesuai dengan sumbu bidang tanah.

Keempat kondisi ini memberi kita delapan kemungkinan dan delapan arah yang memungkinkan.

Jika pemain menekan, misalnya, W dan D secara bersamaan, vektor akan memiliki panjang sekitar 1.4. Namun, jika mereka menekan satu tombol, vektor akan memiliki panjang 1. Kita ingin panjang vektor konsisten, dan tidak bergerak lebih cepat secara diagonal. Untuk melakukannya, kita dapat memanggil metodenya normalized().

#func _physics_process(delta):
#...

if direction != Vector3.ZERO:
direction = direction.normalized()
# Setting the basis property will affect the rotation of the node.
$Pivot.basis = Basis.looking_at(direction)

public override void _PhysicsProcess(double delta)
{
    // ...

    if (direction != Vector3.Zero)
    {
        direction = direction.Normalized();
        // Setting the basis property will affect the rotation of the node.
        GetNode<Node3D>("Pivot").Basis = Basis.LookingAt(direction);
    }
}

Di sini, kami hanya menormalkan vektor jika arahnya memiliki panjang lebih besar dari nol, yang berarti pemain menekan tombol arah.

Kami menghitung arah $Pivotyang dilihat dengan membuat Basis yang melihat ke directionarah tersebut.

Kemudian, kita perbarui kecepatannya. Kita harus menghitung kecepatan tanah dan kecepatan jatuh secara terpisah. Pastikan untuk kembali ke tab sebelumnya sehingga garis berada di dalam fungsi _physics_process()tetapi di luar kondisi yang baru saja kita tulis di atas.

func _physics_process(delta):
#...
if direction != Vector3.ZERO:
#...

# Ground Velocity
target_velocity.x = direction.x * speed
target_velocity.z = direction.z * speed

# Vertical Velocity
if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity
target_velocity.y = target_velocity.y - (fall_acceleration * delta)

# Moving the Character
velocity = target_velocity
move_and_slide()

public override void _PhysicsProcess(double delta)
{
    // ...
    if (direction != Vector3.Zero)
    {
        // ...
    }

    // Ground velocity
    _targetVelocity.X = direction.X * Speed;
    _targetVelocity.Z = direction.Z * Speed;

    // Vertical velocity
    if (!IsOnFloor()) // If in the air, fall towards the floor. Literally gravity
    {
        _targetVelocity.Y -= FallAcceleration * (float)delta;
    }

    // Moving the character
    Velocity = _targetVelocity;
    MoveAndSlide();
}

Fungsi ini CharacterBody3D.is_on_floor()kembali truejika benda bertabrakan dengan lantai dalam bingkai ini. Itulah sebabnya kita menerapkan gravitasi pada benda Playersaat benda berada di udara.

Untuk kecepatan vertikal, kita kurangi percepatan jatuh dikalikan dengan waktu delta setiap frame. Baris kode ini akan menyebabkan karakter kita jatuh di setiap frame, selama karakter tersebut tidak berada di atas atau bertabrakan dengan lantai.

Mesin fisika hanya dapat mendeteksi interaksi dengan dinding, lantai, atau benda lain selama frame tertentu jika terjadi gerakan dan tabrakan. Kita akan menggunakan properti ini nanti untuk mengodekan lompatan.

Pada baris terakhir, kita sebut CharacterBody3D.move_and_slide()which yang merupakan metode kelas yang ampuh CharacterBody3Dyang memungkinkan Anda menggerakkan karakter dengan lancar. Jika karakter tersebut membentur dinding di tengah gerakan, mesin akan mencoba menghaluskannya untuk Anda. Mesin tersebut menggunakan nilai kecepatan bawaan dari CharacterBody3D

Dan itu semua kode yang Anda perlukan untuk menggerakkan karakter di lantai.

Berikut adalah kode lengkap player.gduntuk referensi.

extends CharacterBody3D

# How fast the player moves in meters per second.
@export var speed = 14
# The downward acceleration when in the air, in meters per second squared.
@export var fall_acceleration = 75

var target_velocity = Vector3.ZERO

func _physics_process(delta):
var direction = Vector3.ZERO

if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_back"):
direction.z += 1
if Input.is_action_pressed("move_forward"):
direction.z -= 1

if direction != Vector3.ZERO:
direction = direction.normalized()
$Pivot.basis = Basis.looking_at(direction)

# Ground Velocity
target_velocity.x = direction.x * speed
target_velocity.z = direction.z * speed

# Vertical Velocity
if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity
target_velocity.y = target_velocity.y - (fall_acceleration * delta)

# Moving the Character
velocity = target_velocity
move_and_slide()
using Godot;

public partial class Player : CharacterBody3D
{
    // How fast the player moves in meters per second.
    [Export]
    public int Speed { get; set; } = 14;
    // The downward acceleration when in the air, in meters per second squared.
    [Export]
    public int FallAcceleration { get; set; } = 75;

    private Vector3 _targetVelocity = Vector3.Zero;

    public override void _PhysicsProcess(double delta)
    {
        var direction = Vector3.Zero;

        if (Input.IsActionPressed("move_right"))
        {
            direction.X += 1.0f;
        }
        if (Input.IsActionPressed("move_left"))
        {
            direction.X -= 1.0f;
        }
        if (Input.IsActionPressed("move_back"))
        {
            direction.Z += 1.0f;
        }
        if (Input.IsActionPressed("move_forward"))
        {
            direction.Z -= 1.0f;
        }

        if (direction != Vector3.Zero)
        {
            direction = direction.Normalized();
            GetNode<Node3D>("Pivot").Basis = Basis.LookingAt(direction);
        }

        // Ground velocity
        _targetVelocity.X = direction.X * Speed;
        _targetVelocity.Z = direction.Z * Speed;

        // Vertical velocity
        if (!IsOnFloor()) // If in the air, fall towards the floor. Literally gravity
        {
            _targetVelocity.Y -= FallAcceleration * (float)delta;
        }

        // Moving the character
        Velocity = _targetVelocity;
        MoveAndSlide();
    }
}

Menguji pergerakan pemain kami

Kita akan menempatkan pemain kita di dalam Mainadegan untuk mengujinya. Untuk melakukannya, kita perlu membuat instance pemain dan kemudian menambahkan kamera. Tidak seperti dalam 2D, dalam 3D, Anda tidak akan melihat apa pun jika viewport Anda tidak memiliki kamera yang mengarah ke sesuatu.

Simpan Playeradegan Anda dan buka Mainadegan tersebut. Anda dapat mengeklik tab Utama di bagian atas editor untuk melakukannya.

gambar1

Jika Anda menutup adegan sebelumnya, buka dok FileSystem dan klik dua kali main.tscnuntuk membukanya kembali.

Untuk membuat instance Player, klik kanan pada Mainnode tersebut dan pilih Instantiate Child Scene .

gambar2

Pada popup, klik dua kali player.tscn. Karakter akan muncul di tengah viewport.

Menambahkan kamera

Selanjutnya, mari tambahkan kamera. Seperti yang kita lakukan dengan Player 's Pivot , kita akan membuat rig dasar. Klik kanan pada Mainnode tersebut lagi dan pilih Add Child Node . Buat Marker3D baru , dan beri nama CameraPivot. Pilih CameraPivotdan tambahkan node anak Camera3D ke dalamnya. Pohon adegan Anda akan terlihat seperti ini.

gambar3

Perhatikan kotak centang Pratinjau yang muncul di kiri atas tampilan 3D saat Anda memilih Kamera . Anda dapat mengekliknya untuk melihat pratinjau proyeksi kamera dalam game.

gambar4

Kita akan menggunakan Pivot untuk memutar kamera seolah-olah kamera berada di atas derek. Pertama-tama mari kita bagi tampilan 3D agar dapat bergerak bebas di sekitar lokasi dan melihat apa yang dilihat kamera.

Pada bilah alat tepat di atas viewport, klik View , lalu 2 Viewports . Anda juga dapat menekan pada macOS).Ctrl + 2Cmd + 2

gambar11

gambar5

Pada tampilan bawah, pilih Camera3D Anda dan aktifkan Pratinjau kamera dengan mengeklik kotak centang.

gambar6

Pada tampilan atas, pastikan Camera3D Anda dipilih lalu gerakkan kamera sekitar 19satuan pada sumbu Z (seret panah biru).

gambar7

Di sinilah keajaiban terjadi. Pilih CameraPivot dan putar -45 beberapa derajat di sekitar sumbu X (menggunakan lingkaran merah). Anda akan melihat kamera bergerak seolah-olah terpasang pada derek.

gambar8

Anda dapat menjalankan adegan dengan menekan F6dan menekan tombol panah untuk menggerakkan karakter.

gambar9

Kita dapat melihat beberapa ruang kosong di sekitar karakter karena proyeksi perspektif. Dalam permainan ini, kita akan menggunakan proyeksi ortografis untuk membingkai area permainan dengan lebih baik dan memudahkan pemain untuk membaca jarak.

Pilih Kamera lagi dan di Inspektur , atur Proyeksi ke Ortogonal dan Ukuran ke 19. Karakter sekarang akan terlihat lebih datar dan tanah akan mengisi latar belakang.

Catatan

Saat menggunakan kamera ortogonal di Godot 4, kualitas bayangan terarah bergantung pada nilai Far kamera . Semakin tinggi nilai Far , semakin jauh kamera dapat melihat. Namun, nilai Far yang lebih tinggi juga menurunkan kualitas bayangan karena rendering bayangan harus mencakup jarak yang lebih jauh.

Jika bayangan arah tampak terlalu kabur setelah beralih ke kamera ortogonal, kurangi properti Far kamera ke nilai yang lebih rendah seperti 100. Jangan kurangi properti Far ini terlalu banyak, atau objek di kejauhan akan mulai menghilang.

gambar10

Uji adegan Anda dan Anda seharusnya dapat bergerak ke 8 arah dan tidak tergelincir melalui lantai!

Akhirnya, kita sudah memiliki pergerakan pemain dan tampilan yang sesuai. Selanjutnya, kita akan mengerjakan monster.

Tidak ada komentar:

Posting Komentar