Controler Roll-a-ball (Revizuirea codului, C#, Unity3D, Fizică)

Ethan Bierlein a intrebat.

M-am jucat cu Unity 5 în ultima vreme și, în efortul de a începe să fac un joc real, am construit un controler cu minge asemănător cu cel găsit în tutorialul Unity Roll-a-ball.

În esență, jucătorul controlează o minge mică care se rostogolește în jurul unei „nivel”. Mingea poate accelera cu o viteză cuprinsă între $1\rightarrow10$, în funcție de ceea ce aleg eu (designerul). De asemenea, controlerul calculează manual rezistența la înaintare pentru a crea un „gravitație redusă” senzația de „gravitație redusă”, dar să aibă totuși o senzație de viteză. Tracțiunea este calculată cu ajutorul următoarei formule:

$$text{drag}=frac{text{mărimea vectorului de accelerație}}}{text{un dividend}}}$$$

Mă întreb despre următoarele lucruri:

  • Este adecvat ca controlerul să facă lucruri precum calculul rezistenței la înaintare sau ar trebui ca acest lucru să fie separat într-o zonă separată?
  • În prezent, folosesc un dicționar, fac o buclă prin el, verificând dacă sunt apăsate tastele și apoi aplicând forța dacă este apăsată o tastă. Este aceasta o modalitate bună de a gestiona acest lucru? Va încetini vreodată acest lucru ceva?
  • Există vreo îmbunătățire a performanței care poate fi făcută?
  • Altceva?

BallController.cs

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// This class contains various methods and attributes
/// used to control the "vehicle".
/// </summary>
[System.Serializable]
[RequireComponent(typeof(Rigidbody))]
public class MoveVehicle : MonoBehaviour
{
    /// <summary>
    /// The force of an acceleration. This will be applied
    /// to the ball when it's accelerating.
    /// </summary>
    [Range(1, 10)]
    public float accelerationForce;

    /// <summary>
    /// This determines the drag being exerted on the ball
    /// as it moves. Drag is determined through the formula
    /// drag = accelerationForce / dragDividend
    /// </summary>
    [Range(0, 1000)]
    public float dragDividend;

    private Rigidbody rigidBody;
    private Dictionary<KeyCode, Vector3> keyMappings = new Dictionary<KeyCode, Vector3>() {
        {KeyCode.Space, new Vector3(0, 5.5f, 0)},

        {KeyCode.W, new Vector3(0, 0, 1)},
        {KeyCode.A, new Vector3(-1, 0, 0)},
        {KeyCode.S, new Vector3(0, 0, -1)},
        {KeyCode.D, new Vector3(1, 0, 0)},

        {KeyCode.UpArrow, new Vector3(0, 0, 1)},
        {KeyCode.LeftArrow, new Vector3(-1, 0, 0)},
        {KeyCode.DownArrow, new Vector3(0, 0, -1)},
        {KeyCode.RightArrow, new Vector3(1, 0, 0)}
    };

    /// <summary>
    /// Check if the ball is near to, or touching the
    /// ground. This is used to determine whether the
    /// vehicle can move or not.
    /// </summary>
    public bool IsGrounded()
    { return Physics.Raycast(this.transform.position, -Vector3.up, 0.65f); }

    /// <summary>
    /// Initialize things like our Rigidbody component,
    /// or other things that can only be initialized in
    /// Start.
    /// </summary>
    public void Start()
    { this.rigidBody = GetComponent<Rigidbody>(); }

    /// <summary>
    /// Apply thrust to the ball. The faster the vehicle
    /// gets, the more drag we apply to the rigidbody. This will
    /// create the effect of reaching a "maximum" speed.
    /// </summary>
    public void FixedUpdate()
    {
        foreach(KeyValuePair<KeyCode, Vector3> keyMapping in this.keyMappings)
        {
            if(Input.GetKey(keyMapping.Key) && this.IsGrounded())
            {
                Vector3 objectForce = keyMapping.Value * this.accelerationForce;
                this.rigidBody.drag = objectForce.sqrMagnitude / this.dragDividend;
                this.rigidBody.AddForce(objectForce);
            }
        }
    }
}

2 răspunsuri
Heslacher

În primul rând, permiteți-ne să picăm un pic.

MoveVehicle ar fi un nume frumos pentru o metodă, dar pentru o clasă nu este bine ales. Un nume de clasă ar trebui să fie făcut dintr-un substantiv sau o frază substantivală. Deci, de exemplu VehicleMover sau VehicleController ar fi un nume mult mai bun pentru această clasă.


Metoda în cauză

public void FixedUpdate()
{
    foreach(KeyValuePair<KeyCode, Vector3> keyMapping in this.keyMappings)
    {
        if(Input.GetKey(keyMapping.Key) && this.IsGrounded())
        {
            Vector3 objectForce = keyMapping.Value * this.accelerationForce;
            this.rigidBody.drag = objectForce.sqrMagnitude / this.dragDividend;
            this.rigidBody.AddForce(objectForce);
        }
    }
}  

aici aș sugera să folosiți var în loc de KeyValuePair<KeyCode, Vector3> ceea ce ar face codul dvs. puțin mai curat și este evident că va fi o KeyValuePair<TKey,TValue.

În rest, codul dvs. arată frumos și ordonat. Bună treabă.

Nu știu Unity3D deloc, așa că nu știu dacă este posibil să se schimbe public float accelerationForce; la o proprietate publică. Dacă acest lucru este posibil, v-aș sugera ca în interiorul setterului să schimbați toate valorile proprietății Dictionary astfel încât acestea să reprezinte forța obiectului. Acest lucru ar implica un al doilea tip de colecție sau niște constante pentru a păstra valorile predifinite în prezent ale proprietății curente. Dictionary.

În cazul în care este probabil ca accelerationForce este apelat mai rar decât FixedUpdate() metoda, acest lucru va accelera totul.

Catarg

Fișierul dvs. se numește BallController.cs. Clasa dvs. se numește MoveVehicle.

Problema este că ambele nume sunt greșite. Nu mutați o minge sau un vehicul. Mișcați un jucător. Deci, de ce nu se numește fișierul dvs. PlayerController.cs?

Dacă schimbați forma jucătorului, acesta rămâne tot un jucător. Dar s-ar putea să nu mai fie o minge. PlayerController ar fi și el un nume de clasă frumos. Știu că este numele standard folosit în tutorial, dar se întâmplă să fie unul foarte bun.