2015-11-25 3 views
0

I'am new there. Я изучал классы и старался сделать очень простую платформу. Но теперь у меня проблемы. Я хотел, чтобы класс «Player» столкнулся с двумя объектами класса «Блок», но столкновение не работает для одного из них.Столкновение с более чем одним объектом SDL 2.0-C++

Вот мой код:

#include <iostream> 
#include <SDL.h> 
#include <SDL_image.h> 
#undef main 

class Block 
{ 
private: 
    SDL_Texture *BlockTexture; 
public: 
    Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height); 
    ~Block(); 
    void Draw(SDL_Renderer *renderTarget); 
    SDL_Rect BlockPos; 
}; 
Block::Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height) 
{ 
    SDL_Surface *surface = IMG_Load(filePath.c_str()); 
    { 
     BlockTexture = SDL_CreateTextureFromSurface(renderTarget, surface); 
    } 
    SDL_FreeSurface(surface); 

    BlockPos.x = xPos; 
    BlockPos.y = yPos; 
    BlockPos.w = Width; 
    BlockPos.h = Height; 
} 
Block::~Block() 
{ 
    SDL_DestroyTexture(BlockTexture); 
} 
void Block::Draw(SDL_Renderer *renderTarget) 
{ 
    SDL_RenderCopy(renderTarget, BlockTexture, NULL, &BlockPos); 
} 
class Player 
{ 
private: 
    SDL_Texture *Texture; 
    float moveSpeed; 
    float jumpSpeed; 
    int falling = 0; 
    SDL_Scancode keys [3]; 
public: 
    SDL_Rect PlayerPos; 
    Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY,  int Width, int Height); 
    ~Player(); 

    void Update(float delta, const Uint8 *Keystate); 
    void Draw(SDL_Renderer *renderTarget); 

    bool Collision(Block &p); 
}; 
Player::Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int  PosY, int Width, int Height) 
{ 
    SDL_Surface *surface = IMG_Load(filePath.c_str()); 
    { 
     Texture = SDL_CreateTextureFromSurface(renderTarget, surface); 
    } 
    SDL_FreeSurface(surface); 

    PlayerPos.x = PosX; 
    PlayerPos.y = PosY; 
    PlayerPos.w = Width; 
    PlayerPos.h = Height; 

    keys[0] = SDL_SCANCODE_UP; 
    keys[1] = SDL_SCANCODE_LEFT; 
    keys[2] = SDL_SCANCODE_RIGHT; 

    moveSpeed = 200.f; 
    jumpSpeed = 100.f; 
} 
Player::~Player() 
{ 
    SDL_DestroyTexture(Texture); 
} 
void Player::Update(float delta, const Uint8 *KeyState) 
{ 
    if(KeyState[keys[0]]) 
    { 
     PlayerPos.y -= moveSpeed * delta; 
    } 
    if(KeyState[keys[1]]) 
    { 
     PlayerPos.x -= (moveSpeed/2) * delta; 
    } 
    if(KeyState[keys[2]]) 
    { 
     PlayerPos.x += moveSpeed * delta; 
    } 
    if(falling == 0) 
    { 
     PlayerPos.y += jumpSpeed * delta; 
    } 
} 
void Player::Draw(SDL_Renderer *renderTarget) 
{ 
    SDL_RenderCopy(renderTarget, Texture, NULL, &PlayerPos); 
} 
bool Player::Collision(Block &p) 
{ 
    if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w || 
     PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h) 
    { 
     falling = 0; 
     return true; 
    } 
    else 
     falling = 1; 
     return false; 
} 
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *Renderer) 
{ 
    SDL_Texture *texture = NULL; 
    SDL_Surface *surface = IMG_Load(filePath.c_str()); 
    { 
     texture = SDL_CreateTextureFromSurface(Renderer, surface); 
    } 
    SDL_FreeSurface(surface); 
    return texture; 
} 
int main(int argc, char *argv[]) 
{ 
    SDL_Init(SDL_INIT_EVERYTHING); 

    SDL_Window *window = SDL_CreateWindow("Platform", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); 
    SDL_Renderer *renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 

    int imgFlags = IMG_INIT_PNG; 

    int currentTime = 0; 
    int previousTime = 0; 
    float delta = 0; 

    const Uint8 *Keystate; 

    Player Player(renderTarget, "BlockP.png", 100, 100, 50, 50); 

    Block Block1(renderTarget, "Block.png", 0, 500, 800, 100); 
    Block Block2(renderTarget, "Block.png", 100, 300, 300, 50); 

    bool isRunning = true; 
    SDL_Event ev; 

    while(isRunning) 
    { 
     Keystate = SDL_GetKeyboardState(NULL); 

     Player.Collision(Block1); 
     Player.Collision(Block2); 

     previousTime = currentTime; 
     currentTime = SDL_GetTicks(); 
     delta = (currentTime - previousTime)/1000.0f; 

     Player.Update(delta, Keystate); 

     while(SDL_PollEvent(&ev) != 0) 
     { 
      if(ev.type == SDL_QUIT) 
       isRunning = false; 
     } 
     SDL_RenderClear(renderTarget); 

     Player.Draw(renderTarget); 

     Block1.Draw(renderTarget); 
     Block2.Draw(renderTarget); 

     SDL_RenderPresent(renderTarget); 
    } 
    SDL_DestroyWindow(window); 
    SDL_DestroyRenderer(renderTarget); 
    window = NULL; 
    renderTarget = NULL; 

    SDL_Quit(); 

    return 0; 
} 

ответ

0

Проблема с кодом является то, что каждый вызов Player.Collision переписывает «падающий» переменный.

Player.Collision(Block1); //this call calculates a falling value 
Player.Collision(Block2); //...then this call overwrites falling with a new value 

Так эффективно ваш код тестирует только если игрок сталкиваясь с block2, поэтому столкновения с block1 игнорируются.

В настоящее время ваша функция коллизий:

bool Player::Collision(Block &p) 
{ 
    if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w || 
     PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h) 
    { 
     falling = 0; 
     return true; 
    } 
    else 
     falling = 1; 
     return false; 
} 

Во-первых, ваш "возвращение ложным;" на самом деле не является частью else, так как у вас нет {}. В этом конкретном случае это не имеет никакого значения, поскольку else вызывается, а затем происходит возврат, но ваш отступ предполагает, что вы ожидаете, что «return false»; линия должна быть выполнена как часть блока еще, так что вы должны поставить:

else 
{ 
    falling = 1; 
    return false; 
} 

Далее вы хотите сказать, если вы уже обнаружили столкновение (например, с block1), то не установлены падением на 1, чтобы сделайте это, добавьте оператор if.

else 
{ 
    if(falling != 0) //if we haven't already detected a collision this frame 
    { 
     falling = 1; 
    } 
    return false; 
} 

однако вы должны установить откатиться к 1 в начале каждого кадра, в противном случае, если столкновение обнаружено на одном кадре, то игрок никогда не будет падать на последующих кадрах, даже если они не сталкиваясь с Блок.

В качестве примечания стороны, ваш код Player.Update изменяет позицию игрока в случае падения == 0, это похоже на счетчик интуитивно понятным, как обычно, 0 является ложным и 1 является истинным, поэтому вы, кажется, говорите, если не падаете, а затем обновляете y, где, как и должно быть, при падении обновления y. Лично я использовал бы bool, а не int, чтобы удерживать значение падения, а затем сказать, если (падение) обновление y, это сделает ваш код более четким.

+0

Большое спасибо: D !. Я делал то, что ты сказал. И теперь он отлично работает. – MCF

+0

Нет проблем, как только ваш вопрос будет дан ответ, вы должны пометить ответ как принятый, это поможет предотвратить переполнение стека. – jtedit

Смежные вопросы