Na tej stronie wyjaśniono koncepcje programowania rozgrywki w Unreal Engine (UE) dla użytkowników Unity. Przy opracowywaniu poniższych objaśnień założono, że użytkownik będzie zaznajomiony z Unity C# i będzie chciał nauczyć się UE C++ oraz Blueprintu.
Poniższe przykłady obejmują kilka typowych przypadków użycia programowania rozgrywki w Unity C# oraz sposób implementowania podobnych funkcjonalności w UE.
Tworzenie instancji GameObject / spawnowanie aktora
W Unity do tworzenia nowych instancji obiektów służy funkcja Instantiate. Funkcja ta bierze dowolny typ UnityEngine.Object (GameObject, MonoBehaviour itp.) i tworzy jego kopię.
public GameObject EnemyPrefab;
public Vector3 SpawnPosition;
public Quaternion SpawnRotation;
void Start()
{
GameObject NewGO = (GameObject)Instantiate(EnemyPrefab, SpawnPosition, SpawnRotation);
NewGO.name = "MyNewGameObject";
}W UE dostępne są dwie różne funkcje tworzenia instancji obiektów:
NewObjecttworzy nowe typyUObject.SpawnActorspawnuje typyAActor.
Obiekty UObject i NewObject
Tworzenie podklas UObject w UE w dużym stopniu przypomina tworzenie podklas ScriptableObject w Unity. Opcje te przydają się przy tworzeniu klas rozgrywki, które nie muszą być spawnowane w świecie lub mają dołączone komponenty, jak w przypadku aktorów.
W Unity tworzenie instancji na podstawie utworzonej podklasy ScriptableObject wygląda następująco:
MyScriptableObject NewSO = ScriptableObject.CreateInstance<MyScriptableObject>();W UE tworzenie instancji na podstawie utworzonej podklasy UObject wygląda następująco:
UMyObject* NewObj = NewObject<UMyObject>();AActors i SpawnActor
Aktorów można generować przy użyciu metody SpawnActor zastosowanej do obiektu World (UWorld w C++). Niektóre obiekty UObjects i wszyscy aktorzy udostępniają metodę GetWorld służącą do uzyskania obiektu World.
W poniższym przykładzie używa się tych metod z istniejącymi parametrami spawnowania aktora do emulowania funkcji metody Unity Instantiate.
Przykład
Poniżej znajduje się przykład podklasy AActor, AMyActor. Konstruktor domyślny inicjuje zmienne int32 i USphereComponent*.
Należy zwrócić uwagę na użycie funkcji CreateDefaultSubobject. Ta funkcja tworzy komponenty i przypisuje im domyślne właściwości. Podobiekty utworzone za pomocą tej funkcji działają jak szablon domyślny, więc można je modyfikować w podklasie lub w Blueprincie.
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY()
int32 MyIntProp;
UPROPERTY()
USphereComponent* MyCollisionComp;
Tworzy to klon obiektu AMyActor, zawierający wszystkie zmienne składowe, UPROPERTY i komponenty.
AMyActor* CreateCloneOfMyActor(AMyActor* ExistingActor, FVector SpawnLocation, FRotator SpawnRotation)
{
UWorld* World = ExistingActor->GetWorld();
FActorSpawnParameters SpawnParams;
SpawnParams.Template = ExistingActor;
World->SpawnActor<AMyActor>(ExistingActor->GetClass(), SpawnLocation, SpawnRotation, SpawnParams);
}Rzutowanie z jednego typu do innego
W tym przypadku pobieramy komponent, o którym wiemy, że go mamy, a następnie rzutujemy go do określonego typu i warunkowo wykonujemy jakąś czynność.
Unity
Collider collider = gameObject.GetComponent<Collider>;
SphereCollider sphereCollider = collider as SphereCollider;
if (sphereCollider != null)
{
// ...
}UE C++
UPrimitiveComponent* Primitive = MyActor->GetComponentByClass(UPrimitiveComponent::StaticClass());
USphereComponent* SphereCollider = Cast<USphereComponent>(Primitive);
if (SphereCollider != nullptr)
{
// ...
}Blueprint
W Blueprincie można rzutować za pomocą węzła Cast to. Więcej informacji można znaleźć w sekcji: Casting Quick Start Guide (Skrócony poradnik – rzutowanie).
Niszczenie GameObject / aktora
Niszczenie GameObject / aktora (z jednosekundowym opóźnieniem)
Wyłączanie GameObjects / aktorów
Unity C# C# | UE C++ C++ | Blueprint |
Dostęp do GameObject / aktora z komponentu
Unity C# C++ | UE C++ C++ | Blueprint |
Dostęp do komponentu z GameObject / aktora
Unity
MyComponent MyComp = gameObject.GetComponent<MyComponent>();UE C++
UMyComponent* MyComp = MyActor->FindComponentByClass<UMyComponent>();Blueprint
Znajdowanie GameObjects / aktorów
Unity
// Find GameObject by name
GameObject MyGO = GameObject.Find("MyNamedGameObject");
// Find Objects by type
MyComponent[] Components = Object.FindObjectsOfType(typeof(MyComponent)) as MyComponent[];
foreach (MyComponent Component in Components)
{
// ...
}
UE C++
// Find UObjects by type
for (TObjectIterator<UMyObject> It; It; ++it)
{
UMyObject* MyObject = *It;
// ...
}
// Find Actor by name (also works on UObjects)
AActor* MyActor = FindObject<AActor>(nullptr, TEXT("MyNamedActor"));
Blueprint
Dodawanie tagów do GameObjects / aktorów
Unity
MyGameObject.tag = "MyTag";UE C++
// Actors can have multiple tags
MyActor.Tags.AddUnique(TEXT("MyTag"));Blueprint
Dodawanie tagów do MonoBehaviours / ActorComponents
Unity
// This changes the tag on the GameObject it is attached to
MyComponent.tag = "MyTag";UE C++
// Components have their own array of tags
MyComponent.ComponentTags.AddUnique(TEXT("MyTag"));Porównywanie tagów na GameObjects / aktorach i MonoBehaviours / ActorComponents
Unity
if (MyGameObject.CompareTag("MyTag"))
{
// ...
}
// Checks the tag on the GameObject it is attached to
if (MyComponent.CompareTag("MyTag"))
{
// ...
}UE C++
// Checks if an Actor has this tag
if (MyActor->ActorHasTag(FName(TEXT("MyTag"))))
{
// ...
}Blueprint
UE C++
// Checks if an ActorComponent has this tag
if (MyComponent->ComponentHasTag(FName(TEXT("MyTag"))))
{
// ...
}Blueprint
Fizyka: komponenty RigidBody vs. komponenty prymitywu
W Unity nadanie cechy fizyce GameObject wymaga dodania do niej komponentu RigidBody.
W UE dowolny komponent prymitywu (UPrimitiveComponent w C++) może reprezentować obiekt fizyczny. Do popularnych komponentów prymitywów należą:
Komponenty kształtu (
USphereComponent,UCapsuleComponentitd.)komponenty siatki statycznej;
komponenty siatki szkieletowej.
W przeciwieństwie do Unity, gdzie obowiązki kolizji i wizualizacje są rozdzielone na odrębne komponenty, UE łączy pojęcia "potencjalnej fizyczności" i "potencjalnej widoczności" w jeden komponent prymitywu. Każdy komponent z dowolną geometrią w świecie, który można renderować lub z którym można wchodzić fizycznie w interakcję, jest podklasą UPrimitiveComponent.
Collision Channels, czyli kanały kolizji, to w UE odpowiednik warstw Unity. Aby dowiedzieć się więcej, należy zapoznać się z sekcją Filtrowanie kolizji.
RayCast vs. RayTrace
Unity
GameObject FindGOCameraIsLookingAt()
{
Vector3 Start = Camera.main.transform.position;
Vector3 Direction = Camera.main.transform.forward;
float Distance = 100.0f;
int LayerBitMask = 1 << LayerMask.NameToLayer("Pawn");
RaycastHit Hit;
bool bHit = Physics.Raycast(Start, Direction, out Hit, Distance, LayerBitMask);
UE C++
APawn* AMyPlayerController::FindPawnCameraIsLookingAt()
{
// You can use this to customize various properties about the trace
FCollisionQueryParams Params;
// Ignore the player's pawn
Params.AddIgnoredActor(GetPawn());
// The hit result gets populated by the line trace
FHitResult Hit;
Blueprint
Woluminy wyzwalania
Unity
public class MyComponent : MonoBehaviour
{
void Start()
{
collider.isTrigger = true;
}
void OnTriggerEnter(Collider Other)
{
// ...
}
UE C++
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
// My trigger component
UPROPERTY()
UPrimitiveComponent* Trigger;
AMyActor()
Blueprint
Aby dowiedzieć się więcej na temat konfigurowania reakcji na kolizje, należy zapoznać się z sekcją Kolizja.
Kinematyczne bryły sztywne
Unity
public class MyComponent : MonoBehaviour
{
void Start()
{
rigidbody.isKinematic = true;
rigidbody.velocity = transform.forward * 10.0f;
}
}UE C++
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY()
UPrimitiveComponent* PhysicalComp;
AMyActor()
{
Zdarzenia wprowadzania
Unity
public class MyPlayerController : MonoBehaviour
{
void Update()
{
if (Input.GetButtonDown("Fire"))
{
// ...
}
float Horiz = Input.GetAxis("Horizontal");
float Vert = Input.GetAxis("Vertical");
UE C++
UCLASS()
class AMyPlayerController : public APlayerController
{
GENERATED_BODY()
void SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAction("Fire", IE_Pressed, this, &AMyPlayerController::HandleFireInputEvent);
Blueprint
Właściwości wejściowe w Ustawieniach projektu mogą wyglądać następująco:
Aby dowiedzieć się więcej o konfiguracji danych wejściowych dla projektu UE, należy zapoznać się z sekcją Dane wejściowe.
Dalsze informacje
Aby uzyskać więcej informacji na temat powyższych pojęć, zalecamy zapoznanie się z następującymi sekcjami:
Struktura rozgrywki – obejmuje podstawowe systemy gry, takie jak tryb gry, stan gracza, kontrolery, pionki, kamery i wiele innych.
Architektura rozgrywki – wskazówki dotyczące tworzenia i wdrażania klas rozgrywki.
Samouczki na temat rozgrywki – samouczki dotyczące odtwarzania typowych elementów rozgrywki.