2D-liikkumisen yleiskatsaus

Johdanto

Jokainen aloitteleva pelintekijä on kysynyt samaa: "Kuinka liikutan pelihahmoani?" Riippuen pelisi tyylistä, sinulla voi olla erityisvaatimuksia, mutta yleisesti ottaen liikkuminen useimmissa 2D-peleissä pohjautuu muutamaan perusmalliin.

Käytämme esimerkeissä KinematicBody2D solmua, mutta periaatteet pätevät muihinkin solmutyyppeihin (Area2D, RigidBody2D).

Järjestely

Jokainen alla oleva esimerkki käyttää samaa skenejärjestelyä. Aloita KinematicBody2D solmulla, jolla on kaksi alisolmua: Sprite ja CollisionShape2D. Spriten tekstuurina voit käyttää Godot-ikonia ("icon.png") tai mitä tahansa 2D-kuvaa.

Avaa valikosta Projekti -> Projektin asetukset... ja valitse "Syötekartta"-välilehti. Lisää siihen seuraavat syötetoiminnot (ks. InputEvent tarkempia tietoja varten):

../../_images/movement_inputs.png

8-suuntainen liikkuminen

Tässä esimerkkitilanteessa haluat käyttäjän painavan neljää suuntanäppäintä (ylös/vasemmalle/alas/oikealle tai W/A/S/D) ja liikkuvan valittuun suuntaan. Nimi "8-suuntainen liikkuminen" tulee siitä, että pelaaja voi liikkua viistosti painamalla kahta näppäintä yhtä aikaa.

../../_images/movement_8way.gif

Lisää kinemaattiselle kappaleelle skripti ja lisää siihen seuraava koodi:

extends KinematicBody2D

export (int) var speed = 200

var velocity = Vector2()

func get_input():
    velocity = Vector2()
    if Input.is_action_pressed("right"):
        velocity.x += 1
    if Input.is_action_pressed("left"):
        velocity.x -= 1
    if Input.is_action_pressed("down"):
        velocity.y += 1
    if Input.is_action_pressed("up"):
        velocity.y -= 1
    velocity = velocity.normalized() * speed

func _physics_process(delta):
    get_input()
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 velocity = new Vector2();

    public void GetInput()
    {
        velocity = new Vector2();

        if (Input.IsActionPressed("right"))
            velocity.x += 1;

        if (Input.IsActionPressed("left"))
            velocity.x -= 1;

        if (Input.IsActionPressed("down"))
            velocity.y += 1;

        if (Input.IsActionPressed("up"))
            velocity.y -= 1;

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        velocity = MoveAndSlide(velocity);
    }
}

get_input() funktiossa tarkistamme neljä näppäintapahtumaa ja laskemme ne yhteen saadaksemme nopeusvektorin. Tästä on se etu, että kaksi vastakkaista näppäintä kumoavat toisensa, mutta se johtaa myös siihen, että viistottainen liike on nopeampaa, koska kaksi suuntaa on laskettu yhteen.

Voimme estää sen normalisoimalla nopeuden, mikä tarkoittaa, että asetamme sen pituudeksi 1 ja kerromme sen halutulla nopeudella.

Vihje

Mikäli et ole käyttänyt vektorimatematiikkaa aiemmin tai tarvitset kertausta, voit lukea selostuksen vektoreiden käytöstä Godotissa sivulta Vector math.

Muista

Jos yllä oleva koodi ei tee mitään painaessasi näppäimiä, tarkista että olet asettanut syötetoiminnot oikein tämän oppaan Järjestely osiossa kuvatulla tavalla.

Kiertyminen + liikkuminen

Tämän tyyppistä liikkumista kutsutaan joskus "Asteroids-tyyliksi", koska se muistuttaa kyseisen klassisen arcade-pelin toimintatapaa. Painamalla vasemalle/oikealle kiertää pelihahmoa, kun taas ylös/alas liikuttaa sitä eteenpäin tai taaksepäin siinä suunnassa johon se osoittaa.

../../_images/movement_rotate1.gif
extends KinematicBody2D

export (int) var speed = 200
export (float) var rotation_speed = 1.5

var velocity = Vector2()
var rotation_dir = 0

func get_input():
    rotation_dir = 0
    velocity = Vector2()
    if Input.is_action_pressed("right"):
        rotation_dir += 1
    if Input.is_action_pressed("left"):
        rotation_dir -= 1
    if Input.is_action_pressed("down"):
        velocity = Vector2(-speed, 0).rotated(rotation)
    if Input.is_action_pressed("up"):
        velocity = Vector2(speed, 0).rotated(rotation)

func _physics_process(delta):
    get_input()
    rotation += rotation_dir * rotation_speed * delta
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;
    [Export] public float rotationSpeed = 1.5f;

    public Vector2 velocity = new Vector2();
    public int rotationDir = 0;

    public void GetInput()
    {
        rotationDir = 0;
        velocity = new Vector2();

        if (Input.IsActionPressed("right"))
            rotationDir += 1;

        if (Input.IsActionPressed("left"))
            rotationDir -= 1;

        if (Input.IsActionPressed("down"))
            velocity = new Vector2(-speed, 0).Rotated(Rotation);

        if (Input.IsActionPressed("up"))
            velocity = new Vector2(speed, 0).Rotated(Rotation);

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        Rotation += rotationDir * rotationSpeed * delta;
        velocity = MoveAndSlide(velocity);
    }
}

Tässä olemme lisänneet kaksi uutta muuttujaa kiertymissuunnan ja -nopeuden seuraamiseksi. Jälleen kerran, molempien näppäimien yhdenaikainen painaminen kumoaa toisensa, eikä kiertymistä tapahdu. Kiertyminen lisätään suoraan kappaleen rotation ominaisuuteen.

Nopeuden asettamiseksi käytämme Vector2.rotated() metodia niin, että se osoittaa samaan suuntaan kuin kappale. rotated() on hyödyllinen vektorifunktio, jota voit käyttää useissa tilanteissa, joissa muutoin tarvitsisit trigonometrisia funktioita.

Kiertyminen + liikkuminen (hiirellä)

Tämä liikkumistyyli on muunnelma edellisestä. Tällä kertaa suuntaa asetetaan hiiren sijainnilla näppäimistön sijaan. Pelihahmo "katsoo" aina hiiren osoittimen suuntaan. Eteenpäin/taaksepäin syötteet pysyvät kuitenkin samana.

../../_images/movement_rotate2.gif
extends KinematicBody2D

export (int) var speed = 200

var velocity = Vector2()

func get_input():
    look_at(get_global_mouse_position())
    velocity = Vector2()
    if Input.is_action_pressed("down"):
        velocity = Vector2(-speed, 0).rotated(rotation)
    if Input.is_action_pressed("up"):
        velocity = Vector2(speed, 0).rotated(rotation)

func _physics_process(delta):
    get_input()
    velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 velocity = new Vector2();

    public void GetInput()
    {
        LookAt(GetGlobalMousePosition());
        velocity = new Vector2();

        if (Input.IsActionPressed("down"))
            velocity = new Vector2(-speed, 0).Rotated(Rotation);

        if (Input.IsActionPressed("up"))
            velocity = new Vector2(speed, 0).Rotated(Rotation);

        velocity = velocity.Normalized() * speed;
    }

    public override void _PhysicsProcess(float delta)
    {
        GetInput();
        velocity = MoveAndSlide(velocity);
    }
}

Tässä käytämme Node2D solmun look_at() metodia osoittamaan pelaaja annettun sijainnin suuntaan. Ilman tätä funktiota, saisit saman aikaan asettamalla kulman tällä tavalla:

rotation = get_global_mouse_position().angle_to_point(position)
var rotation = GetGlobalMousePosition().AngleToPoint(Position);

Napsauta-ja-liiku

Tämä viimeinen esimerkki käyttää ainoastaan hiirtä hahmon ohjaamiseen. Ruudun napsauttaminen saa pelaajan siirtymään kohdepaikkaan.

../../_images/movement_click.gif
extends KinematicBody2D

export (int) var speed = 200

var target = Vector2()
var velocity = Vector2()

func _input(event):
    if event.is_action_pressed("click"):
        target = get_global_mouse_position()

func _physics_process(delta):
    velocity = position.direction_to(target) * speed
    # look_at(target)
    if position.distance_to(target) > 5:
        velocity = move_and_slide(velocity)
using Godot;
using System;

public class Movement : KinematicBody2D
{
    [Export] public int speed = 200;

    public Vector2 target = new Vector2();
    public Vector2 velocity = new Vector2();

    public override void _Input(InputEvent @event)
    {
        if (@event.IsActionPressed("click"))
        {
            target = GetGlobalMousePosition();
        }
    }

    public override void _PhysicsProcess(float delta)
    {
        velocity = Position.DirectionTo(target) * speed;
        // LookAt(target);
        if (Position.DistanceTo(target) > 5)
        {
            velocity = MoveAndSlide(velocity);
        }
    }
}

Huomaa distance_to() tarkistus, jonka teemme ennen liikkumista. Ilman tätä testiä, kappale "tärisisi" saavutettuaan kohdesijainnin sen liikkuessa hivenen sijainnin ohi ja yrittäessä liikkua takaisin, vain liikkuakseen liian pitkälle ja toistaakseen saman.

Kommentoinnin poistaminen look_at() riviltä saa kappaleen kääntymään myös osoittamaan liikkumissuuntaansa, jos niin haluat.

Vihje

Tätä tekniikaa voi myös käyttää pohjana "seuraavalle" hahmolle. target sijainti voi olla minkä tahansa objektin, jota haluat liikuttaa.

Yhteenveto

Nämä koodiesimerkit saattavat olla hyödyllisiä aloituspisteitä omiin projekteihisi. Voit vapaasti käyttää niitä ja kokeilla mitä voisit saada aikaiseksi.

Voit ladata tämän esimerkkiprojektin täältä: 2D_movement_demo.zip