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

28.03.2011 - Mateusz Osowski
TrudnośćTrudność

Wyposażanie postaci

Mamy już możliwość sprawnego przeglądania ekwipunku. Nadszedł czas na wybór broni. Chcemy, aby postać miała wybraną broń przy sobie i potrafiła ją wyciągnąć. Byłoby wyśmienicie, gdyby pozycja broni czy to schowanej, czy wyciągniętej była dopasowana do ruchów postaci. Skorzystamy z nasuwającego się, prostego rozwiązania - animacji szkieletowej. Szkielet postaci poszerzymy o kość miecza wychodzącą z dłoni i kość pochwy miecza. Ogre udostępnia funkcje pozwalające wygodnie przypiąć obiekt w odpowiednie miejsce.

W grze mogą się pojawiać przedmioty różnych typów. Do rozróżnienia tych typów możemy wykorzystać dziedziczenie. DescribedProfile będzie więc typem ogólnym. Stwórzmy klasę dla mieczy:

1
2
3
4
5
6
7
8
9
10
public class ItemSword : DescribedProfile
{
  public float Damage;
  public Vector3 HandleOffset;
 
  public new ItemSword Clone()
  {
    return (ItemSword)MemberwiseClone();
  }
}
ItemSword.cs


Pole HandleOffset będzie przechowywać przesunięcie uchwytu miecza względem jego środka ciężkości. Pamiętajmy, że siatki wykorzystywane w grze powinny być wyśrodkowane przed eksportowaniem do Ogra.

Przejdźmy do klasy Character. Zaczniemy od wyrzucania ekwipunku. To konieczna funkcjonalność. Własności klasy DescribedProfile czynią implementację wyrzucania banalną:

1
2
3
4
5
6
7
8
9
10
11
12
public bool DropItem(int itemIndex)
{               
  if (!Inventory[itemIndex].IsEquipment)
  {
    Described item = new Described(Inventory[itemIndex]);
    item.Position = Position + Orientation * Vector3.UNIT_Z*0.2f;
    Engine.Singleton.ObjectManager.Add(item);
    Inventory.RemoveAt(itemIndex);
    return true; // Udało się wyrzucić przedmiot
  }
  return false;
}
Character.cs


Tworzymy nowy obiekt na podstawie zapamiętanego na liście ekwipunku profilu i pozycjonujemy obiekt 20 cm przed postacią. Jeżeli tworzylibyśmy go zbyt daleko, w niektórych sytuacjach mógłby się tworzyć za ścianami planszy i przepadać. Zakładamy też, że wyrzucany przedmiot nie jest wykorzystywany przez postać.

1
2
ItemSword _Sword;
Entity SwordEntity;
Character.cs


Do klasy dopisujemy prywatne pole _Sword i obiekt siatki dla miecza.

Dopiszmy teraz metody ubierające miecz.

1
2
3
4
5
6
7
8
9
10
11
12
public ItemSword Sword
{
  get { return _Sword; }
  set
  {
    if (SwordEntity != null)
    {
      Entity.DetachObjectFromBone(SwordEntity);
      Engine.Singleton.SceneManager.DestroyEntity(SwordEntity);
      _Sword.IsEquipment = false;
      SwordEntity = null;
    }
Character.cs


Podczas ubierania miecza musimy usunąć stary, jeśli istnieje. Wywołanie DetachObjectFromBone() jest konieczne. Ogre nie pozwala na usuwanie obiektów graficznych związanych z węzłami i innymi obiektami. Dodatkowo czyścimy flagę IsEquipment, przez co obiekt będzie można wyrzucić i nie będzie podświetlany na liście.

1
2
3
4
5
6
7
8
9
10
    if (value != null)
    {
      SwordEntityEngine.Singleton
       .SceneManager.CreateEntity(value.MeshName);                   
      Entity.AttachObjectToBone(
        "LongswordSheath", 
        SwordEntity, Vector3.UNIT_Z.GetRotationTo(-Vector3.UNIT_Y),
        value.HandleOffset);
      value.IsEquipment = true;
    }
Character.cs, Sword


Tworzymy nowy obiekt Entity i podpinamy go do kości pochwy miecza - LongswordSheath (w przykładowym szkielecie kość ta znajduje się na plecach postaci. Dodatkowo istnieje kość SwordSheath przy udzie). Nadajemy mieczowi przesunięcie, a także obrót, ponieważ ostrze miecza zostało wymodelowane wzdłuż osi Z, a kość domyślnie przebiega oś pionową. Odwracamy miecz do góry nogami, by leżał rękojeścią do góry, inaczej bohater mógłby pokaleczyć sobie ręce chwytając go.

Odwiedźmy teraz klasę HumanController, a dokładniej jej metodę HandleInventory. Wykorzystajmy metody wyrzucania przedmiotu i przypinania broni.

1
2
3
4
5
6
7
8
9
10
11
if (Engine.Singleton.IsKeyTyped(MOIS.KeyCode.KC_LMENU))
{
  if (HUDInventory.SelectIndex != -1)
  {
    if (Character.DropItem(HUDInventory.SelectIndex))
    {
      HUDInventory.SelectIndex = HUDInventory.SelectIndex;
      HUDInventory.UpdateView();
    }
  }
}
HumanController, HandleInventory()


Za wyrzucanie odpowiadać będzie lewy klawisz Alt. Jeżeli uda się wyrzucić przedmiot (nie będzie on ubrany) - wymuszamy aktualizację zaznaczenia i odświeżamy listę.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (Engine.Singleton.IsKeyTyped(MOIS.KeyCode.KC_RCONTROL))
{
  if (HUDInventory.SelectIndex != -1)
  {
    if (Character.Inventory[HUDInventory.SelectIndex] is ItemSword)
    {
      if (Character.Sword != Character.Inventory[HUDInventory.SelectIndex]) 
        Character.Sword = 
          Character.Inventory[HUDInventory.SelectIndex] as ItemSword;
      else
        Character.Sword = null;
      HUDInventory.UpdateItem(HUDInventory.SelectIndex);
    }
  }
}
HumanController, HandleInventory()


Do ubierania broni używać się będzie prawego Ctrl. Sprawdzamy czy wybrany przedmiot jest mieczem (5) i czy jest różny od aktualnie wybranego (7). Korzystamy z metody aktualizującej wybrany element listy do włączenia lub wyłączenia podświetlenia.

Pamiętajmy też o tym, by przerobić profil mieczna na typ ItemSword i określić pozycję rękojeści:

1
2
swordProfile.Damage = 1;
swordProfile.HandleOffset = new Vector3(0, 0.4f, 0);
Program.cs, Main()


To już wszystko, miecz powinno dać się ubrać, zdjąć i wyrzucić. Mamy już solidne podstawy systemu wyposażenia postaci. Kolejnym działaniem, które podejmiemy, będzie sprawienie, by postać mogła używać broni. Zanim jednak będziemy w stanie to zrobić, warto dokonać zmian. Aktualna realizacja stanów postaci pozostawia wiele do życzenia, obecna prostota szybko obróci się przeciw nam. Istnieje jednak ratunek w postaci drzewa decyzyjnego. O tym, a także o płynnych przejściach między animacjami dowiecie się w następnej części cyklu.

Nowy model i szkielet

Aktualny kod źródłowy

Nowy model postaci (.blend)

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

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com