Застрял в создании движка движения в 2D-игре

Я делаю движок для своей 2D-игры с видом сверху, но застрял, пытаясь решить следующую проблему:

  • Игрок может перемещаться с помощью клавиш со стрелками, которые ускоряют вас в соответствующих направлениях. Существует трение, поэтому вы перестаете двигаться после отпускания клавиш, хотя и не сразу.
  • Когда вы удерживаете две перпендикулярные клавиши, вы ускоряетесь в этом направлении на 45 ° с той же скоростью, что и на одной оси.
  • Существует максимальная скорость, выше которой вы не можете ускориться при ходьбе, очевидно, что это также ограничивает вашу максимальную скорость ходьбы. Вы можете быть сбиты с толку и тем самым превысить эту скорость.
  • Если вы двигаетесь быстрее макс. walkpeed, вы можете замедлиться быстрее, если будете удерживать клавиши в противоположном (-ых) направлении (-ях)

Псевдокод для первой точки, без трения:

gameTick(){

  tempX += LeftKeyHeld ? -1 : 0;
  tempX += RightKeyHeld ? 1 : 0;
  tempY += UpKeyHeld ? -1 : 0;
  tempY += DownKeyHeld ? 1 : 0;
  ratio = 0.71;

  if( |tempX| == |tempY| ) {
    tempX =tempX* ratio;
    tempY =tempY* ratio;
  }
  player.x += tempX;
  player.y += tempY;
}

Я могу решить проблему трения (получить длину вектора движения, уменьшить ее за счет трения, спроецировать обратно с тем же соотношением x: y), однако я не могу обернуть голову вокруг достижения maxSpeed.

Я попробовал решение, не позволяющее игроку вообще ходить, когда скорость выше maxSpeed, но это нарушает пункт 4. Кроме того, у него был неприятный побочный эффект: когда вы двигались на MaxSpeed ​​влево и начинали нажимать вниз, движение направление не изменилось или почти не изменилось.

Затем я начал думать о многочисленных продуктах, различиях и других вещах с векторами, но в основном я не мог больше следить за ними или столкнулся с ранними проблемами.

Итак, в заключение, может ли кто-нибудь объяснить систему, которая соответствует всем вышеперечисленным пунктам, или указать на статью, в которой объясняется, как такая система может быть реализована? Не беспокойтесь о том, чтобы предложить что-то сложное, я могу понять даже сложные концепции через некоторое время.

Спасибо за вашу помощь!


2d
person Szoltomi    schedule 31.05.2011    source источник


Ответы (3)


arrow_upward
1
arrow_downward

Извините, что не позволил вам думать об этом больше суток, но мне удалось решить эту проблему, и это не две строчки кода. (Хотя все равно спасибо всем за идеи)

Поскольку я ленив и устал, я не буду менять его на псевдокод, кроме следующих двух методов:

updateGame(){
  player.walk();
  player.move();
}
player.move(){
  player.x += player.speedX
  player.y += player.speedY
}

И код (java):

public void walk() {
    float tempX = 0;
    float tempY = 0;
    float accelX;
    float accelY;
    float nextSpeedX;
    float nextSpeedY;
    float nextSpeed;
    float speed;
    tempX += walkLeft ? -1 : 0;
    tempX += walkRight ? 1 : 0;
    tempY += walkUp ? -1 : 0;
    tempY += walkDown ? 1 : 0;

    if (Math.abs(tempX) == Math.abs(tempY)) {
        tempX = (float) tempX * rat;
        tempY = (float) tempY * rat;
    }

    accelX = tempX * (float) runSpeed;
    accelY = tempY * (float) runSpeed;
    speed = (float) Math.sqrt(speedX * speedX + speedY * speedY);
    nextSpeedX = speedX + accelX;
    nextSpeedY = speedY + accelY;
    nextSpeed = (float) Math.sqrt(nextSpeedX * nextSpeedX + nextSpeedY * nextSpeedY);

    if (nextSpeed > maxSpeed) { //can't accelerate by running
        if (nextSpeed > speed) {  //wants to accelerate
            if (speed > maxSpeed) {  //the current speed is larger than maximum.
                float diff = (float)(speed / nextSpeed);
                float greenX = nextSpeedX*diff;
                float greenY = nextSpeedY*diff;
                accelX = greenX-speedX;
                accelY = greenY-speedY;
            } else { //speed <= maxspeed
                float diff = (float)(maxSpeed / nextSpeed);
                float greenX = nextSpeedX*diff;
                float greenY = nextSpeedY*diff;
                accelX = greenX-speedX;
                accelY = greenY-speedY;
            }
        } else { //wants to slow! allow it!
            //acceleration doesn't need to be changed
        }
    } else { //no problem, allow it!
        //acceleration doesn't need to be changed
    }
    speedX += accelX;
    speedY += accelY;
}

Можно было бы короче, можно было бы немного оптимизировать, но это работает. Я надеюсь, что это поможет любому, кто столкнется с этой проблемой в будущем.

person Szoltomi    schedule 01.06.2011

arrow_upward
0
arrow_downward

Добавьте в низ:

 If (|tempX|>maxSpeed)
   tempX=maxSpeed*sign(tempX);

 If (|tempY|>maxSpeed)
   tempY=maxSpeed*sign(tempX);

Где int sign (x) {if x ‹0 return -1; }

person Liran Orevi    schedule 31.05.2011
comment
Но если вы идете, например. вниз + влево, ваша скорость в этом диагональном направлении будет sqrt (2 * maxspeed * maxspeed) = 1,41. Это в некоторой степени относится к пункту 2, я мог бы написать этого уборщика. - person Szoltomi; 31.05.2011
comment
@Szoltomi: Мне кажется, что-то вроде If (|tempX, tempY| > maxSpeed) { tempX = sign(tempX)*maxSpeed*ratio; tempY=sign(tempY)*maxSpeed*ratio; } подойдет. - person JAB; 31.05.2011
comment
Спасибо, я думаю, это быстрее закодировать, чем проверять теорию на ошибки. Скоро сообщу о результате. - person Szoltomi; 31.05.2011
comment
Что возвращает знак (x), когда (x ›= 0)? А также баги: запускается игроком с астрономической скоростью. У меня также есть другие переменные, которые я должен включить, так что это не очень простая вставка кода: P Также: мой динамический генератор мира работает астрономически быстро - person Szoltomi; 31.05.2011
comment
@Szoltomi, наверное, 1, я думаю, код должен быть: int sign (x) {return x ‹0? -1: 1; } - person Edison Gustavo Muenz; 31.05.2011
comment
@Edison: Да, я просто использовал sign(x), чтобы указать, что нужно учитывать знак tempX / tempY. - person JAB; 31.05.2011
comment
Извините, мне не удалось заставить ваше решение работать. Не могли бы вы объяснить, что думаете? С другой стороны, я сделал другое решение, которое, похоже, сработало. Сделал большой пояснительный ответ, но решил провести заключительный тест перед публикацией. И увидел, что это нарушает вторую часть части 3. AAARGH. вырывает волосы. Вернуться к доске для рисования... - person Szoltomi; 31.05.2011

arrow_upward
0
arrow_downward

Я бы предложил связать определенную скорость с игроком в дополнение к положению и проверять эту скорость только на maxSpeed ​​при нажатии клавиш со стрелками.

Если скорость ДЕЙСТВИТЕЛЬНО превышает maxSpeed, но при этом нажимаются клавиши со стрелками с противоположной стороны, то вы должны оставить текущую скорость выше maxSpeed ​​и просто применить отрицательное ускорение.

person JAB    schedule 31.05.2011
comment
Псевдокод сильно упрощен, у меня действительно есть отдельные переменные speedX и Y, но я их отредактировал. Однако с вашим предложением я столкнулся с проблемой, которую я уже написал: если вы переедете, например. left, и начните удерживать left + down, вы не разгонитесь. - person Szoltomi; 31.05.2011
comment
@Szoltomi: В таком случае вы должны замедлить движение влево, поскольку движение вниз ускоряется. Это хорошо сочетается с вашим вторым условием. - person JAB; 01.06.2011