Tworzenie gry w C# z użyciem silnika Ogre - cz.3

10.10.2010 - Mateusz Osowski
TrudnośćTrudność


Posiadamy już etykiety tekstowe. Wykorzystamy je teraz w praktyce - sprawimy, że nad widzianym przez postać obiektem zostanie wyświetlona jego nazwa określona odpowiednim polem jego profilu. Wraz z implementowaniem tej funkcjonalności wprowadzimy klasę kontrolera postaci - interfejsem pośredniczącym pomiędzy obiektem postaci gracza, a samym graczem.

Kontroler postaci

Dobrze będzie, jeśli postacie kontrolowane będą poprzez specjalne klasy kontrolerów. Dzięki temu zyskujemy pewną ogólność w projekcie silnika - postacie będą mogły być kontrolowane przez program lub przez człowieka. Na chwilę obecną interesuje nas jedynie możliwość kontroli postaci przez człowieka, więc nie będziemy tworzyć abstrakcji.
Wprowadź do projektu klasę HumanController:
1
2
3
4
5
class HumanController
{
  public Character Character;
  SelectableObject FocusObject;
  TextLabel3D TargetLabel;
HumanController.cs


Pole Character określać będzie obiekt postaci, z którym związany jest kontroler. Pole FocusObject przechowywać będzie referencję do obiektu widzianego przez postać. W przyszłości, w sytuacji, gdy postać będzie widziała więcej niż jeden obiekt gracz będzie mógł przemieszczać się po liście widzianych obiektów za pomocą skrótu klawiszowego, dzięki czemu nie będzie musiał manewrować postacią, by skupić uwagę postaci na żądanym przedmiocie. Pole TargetLabel stanowić będzie obiekt etykiety widzianego przedmiotu.
1
2
3
4
5
6
7
8
  public HumanController()
  {
    TargetLabel = Engine.Singleton.Labeler.NewTextLabel3D(
      "Primitive", 
      0.04f, 
      new ColourValue(0.7f, 0.4f, 0), 
      new ColourValue(1, 1.0f, 0.6f));
  }
HumanController.cs


Konstruktor tworzy obiekt etykiety. Odwołanie do obieku Labler sugeruje, że konstruktor tego kontrolera powinien być wywołany po zainicjowaniu wszystkich dotychczasowych komponentów silnika.
1
2
3
4
5
6
  public void Update()
  {
    if (Character != null)
    {
      Quaternion rotation = new Quaternion();
      rotation.FromAngleAxis(new Degree(2), Vector3.UNIT_Y);
HumanController.cs


Metoda aktualizująca kontroler będzie wywoływana wraz z aktualizacją mechaniki, więc nie musimy się przejmować skalowaniem rotacji postaci względem czasu renderowania klatki.
1
2
3
4
5
6
7
8
      if (Engine.Singleton.Keyboard.IsKeyDown(MOIS.KeyCode.KC_LEFT))
        Character.Orientation *= rotation;
      if (Engine.Singleton.Keyboard.IsKeyDown(MOIS.KeyCode.KC_RIGHT))
        Character.Orientation *= rotation.Inverse();      
      if (Engine.Singleton.Keyboard.IsKeyDown(MOIS.KeyCode.KC_UP))
        Character.State = Character.CharacterState.WALK;
      else
        Character.State = Character.CharacterState.IDLE;
HumanController.cs, Update()


Powyższy kod jest został przeniesiony z pętli głównej z metody Main() klasy Program.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      if (Character.Contacts.Count > 0)
      {
        SelectableObject contact = Character.Contacts[0] as SelectableObject;
        FocusObject = contact;
        TargetLabel.Caption = contact.DisplayName;
        TargetLabel.Position3D = contact.Position + contact.DisplayNameOffset;
        TargetLabel.IsVisible = true;
      }
      else
      {
        FocusObject = null;
        TargetLabel.IsVisible = false;
      }
    }
  }
HumanController.cs, Update()


W zależności od tego, czy na liście widzianych przez postać obiektów figuruje niezerowa ilość elementów ustalamy pole FocusObject na pierwszy z widzianych obiektów (4), a także ustalmy treść i pozycję etykiety obiektu (5,6). Pozycja etykiety jest określana przez pozycję samego obiektu oraz wektor przesunięcia etykiety względem jego środka.

Pozostaje dodać instancję napisanego kontrolera do klasy silnika:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  public HumanController HumanController;  
  ...  
  public void Initialise()
  {
    ...
    HumanController = new HumanController();
  } 
  
  public void Update()
  {
    ...
    while (TimeAccumulator >= FixedTimeStep)
    {
      NewtonWorld.Update(FixedTimeStep);
      HumanController.Update();
      ...
    }   
  }  
  ...
Engine.cs


Jak można zauważyć, dodawanie komponentów aktualizowanych w stałym odstępie czasu jest dość schematyczne. W związku z tym warto rozważyć przebudowanie klasy Engine w przyszłości.

Oczywiście z metody Main() należy usunąć kod, który został przejęty przez kontroler postaci. Ponadto musimy związać postać gracza z kontrolerem:
1
    Engine.Singleton.HumanController.Character = player;
Program.cs, Main()


Od tej chwili w momencie podejścia postaci do utworzonych wcześniej dekoracyjnych waz powinna zostać wyświetlona ich nazwa:



Aktualny kod źródłowy

5
Twoja ocena: Brak Ocena: 5 (3 ocen)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com