Microsoft XNA, część 2

10.05.2010 - Marcin Oczeretko
TrudnośćTrudność

    Poprzednia część tego artykułu skończyła się w momencie, gdy uporządkowaliśmy kod oraz zadbaliśmy o ładowanie zasobów, rysowanie obiektów na ekranie i poruszanie postacią. Drugą część zaczniemy od dopracowania ostatniego z tych elementów.

    Wykorzystamy nieco wiedzy z fizyki i osiągniemy całkiem interesujący efekt. Gdy naciśnięty będzie przycisk odpowiedzialny za poruszanie, postać będzie stopniowo przyspieszać. Jeśli przycisk zostanie puszczony, to prędkość będzie sukcesywnie maleć. Aby całość wyglądała sensownie, ustalimy też minimalną wartość prędkości gracza - jeśli nie będzie osiągnięta, to postać zatrzyma się. Do pełni szczęścia brakuje nam jeszcze tylko jakiegoś ograniczenia na to, jak szybko można się przemieszczać, umożliwienia skoku jedynie wtedy, gdy stoimy na podłożu i siły grawitacji, która nas do tego podłoża z powrotem przyciągnie. Zadeklarujmy oraz zainicjujmy w klasie Player wszystkie potrzebne obiekty i stałe:

1
2
3
4
5
6
7
private static readonly Vector2 maxSpeed = new Vector2(6, 10),
                                minSpeed = new Vector2(0.5f, 8),
                                speedGain = new Vector2(1.45f, 0),
                                speedFall = new Vector2(0.9f, 0),
                                gravity = new Vector2(0,0.2f);
                                
private Vector2 speed = Vector2.Zero;                                

    Wartości maxSpeed i minSpeed nakładać będą pewne ograniczenia na to jak szybko (i jak wolno) poruszać się może gracz, speedGain i speedFall pozwolą na ustalenie tego, jak będzie wzrastać (maleć) przyspieszenie postaci w zależności od tego czy naciśnięty jest przycisk odpowiedzialny za ruch, czy nie. W gravity przechowywać będziemy wartość wektora siły grawitacji.

    Aby nie tworzyć kodu na próżno, napiszmy może od razu nieco więcej niż tylko lepsze poruszanie postacią. Do gry będziemy potrzebowali co najmniej dwóch graczy, zatem przystosujmy do tego klasę Player. Każdy gracz będzie miał wydzieloną część ekranu, w której będzie się mógł przemieszczać. Informację o tym przechowujmy w obiekcie bounds typu Rectangle. Przydałoby się również, abyśmy mogli skonfigurować to, jakimi klawiszami poruszamy obiektem, dodajmy zatem pola keyUp, keyDown, keyLeft, keyRight. Oczywiście postać po prawej stronie boiska powinna "patrzeć" w lewo, a ta z lewej - w prawo. Niech w zmiennej flip znajduje się informacja o tym, czy rysunek należy odbić symetrycznie przed narysowaniem go na ekranie. Wszystkie te wartości przekazywane będą w konstruktorze, tak samo jak i początkowa pozycja. Dodajmy więc następujące pola:

1
2
3
private Rectangle bounds;
private Keys keyUp, keyDown, keyLeft, keyRight;
private bool flip;

    A konstruktor zmodyfikujmy w taki sposób:

1
2
3
4
5
6
7
8
9
10
11
12
public Player(Rectangle bounds, Vector2 position, bool flip, Keys keyUp,
              Keys keyDown, Keys keyLeft, Keys keyRight, Game game)
            : base(game)
{
    this.bounds = bounds;
    this.position = position;
    this.keyUp = keyUp;
    this.keyDown = keyDown;
    this.keyLeft = keyLeft;
    this.keyRight = keyRight;
    this.flip = flip;
}

    Teraz w metodzie Update() zajmiemy się pobieraniem informacji o naciśniętych klawiszach i odpowiednim modyfikowaniem wektora prędkości postaci (obiekt speed):

Pokaż/ukryj kod metody Update()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public override void Update(GameTime gameTime)
{
    if (Keyboard.GetState().IsKeyDown(keyLeft))
    {
        if (-speed.X < minSpeed.X)
            speed.X = -minSpeed.X;
        else
        {
            if (-speed.X < maxSpeed.X)
                speed.X *= speedGain.X;
 
            if (-speed.X > maxSpeed.X)
                speed.X = -maxSpeed.X;
        }
 
    }
    else if (Keyboard.GetState().IsKeyDown(keyRight))
    {
        if (speed.X < minSpeed.X)
            speed.X = minSpeed.X;
        else
        {
            if (speed.X < maxSpeed.X)
                speed.X *= speedGain.X;
 
            if (speed.X > maxSpeed.X)
                speed.X = maxSpeed.X;
        }
    }
    else
    {
        if (Math.Abs(speed.X) > minSpeed.X)
            speed.X *= speedFall.X;
        else
            speed.X = 0;
    }
 
    if (Keyboard.GetState().IsKeyDown(keyUp)
        && position.Y + texture.Height == bounds.Bottom)
    {
        speed.Y = -minSpeed.Y;
    }
    else
    {
 
        if (position.Y + texture.Height < bounds.Bottom)
        {
            if (Keyboard.GetState().IsKeyDown(keyDown))
                speed += 2*gravity;
            else
                speed += gravity;
        }
       
        if (speed.Y > maxSpeed.Y)
            speed.Y = maxSpeed.Y;
    }
 
    position += speed;
    base.Update(gameTime);
            
}

    W linijkach $ 3-36 $ zajmujemy się ruchem w poziomie, czyli sytuacjami, gdy naciśnięty jest klawisz ruchu w lewo ($ 3-16 $) lub w prawo ($ 17-29 $), albo też żaden z tych dwóch ($ 30-36 $).

    Gdy jakiś klawisz jest naciśnięty,to:

  1. jeśli prędkość jest mniejsza niż minimalna, to zwiększamy ją do tej wartości ($ 5-6 $, $ 19-20 $),

  2. jeśli prędkość jest większa niż minimalna, to zwiększamy ją speedGain razy ($ 9-10 $, $ 23-24 $) i następnie uniemożliwiamy przekroczenie górnej granicy na szybkość poruszania($ 12-13 $, $ 26-27 $).

    Jeśli nie naciśnięto żadnego z dwóch klawiszy odpowiedzialnych za ruch w poziomie, to prędkość spada ($ 32-33 $), a gdy będzie dostatecznie niewielka, to postać zatrzymuje się ($ 34-35 $).

    Gdy naciśnięty zostanie przycisk odpowiedzialny za skok, a postać stoi na podłożu ($ 38-42 $), to ustawiamy przyspieszenie w pionie na ustaloną wartość (dostatecznie dużą, aby możliwe było osiągnięcie jakiejś sensownej wysokości). W innym wypadku wpływamy na gracza siłą grawitacji ($ 48-51 $), dodatkowo podwojoną, jeśli naciska klawisz "w dół" ($ 48-49 $).

    Na końcu aktualizujemy pozycję gracza, dodając do niej wartości z obiektu speed ($ 58 $).

5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com