Por exemplo, o famoso jogo Flappy Bird, ou qualquer coisa desse tipo, é o jogador (neste caso, o pássaro ou a câmera que você preferir) avançando ou o mundo inteiro se movendo para trás (o pássaro muda apenas a posição Y e tem uma posição X constante)?
game-mechanics
platformer
Lendrit Ibrahimi
fonte
fonte
Respostas:
Discordo um pouco da resposta de Philipp ; ou pelo menos com a forma como ele a apresentou. Dá a impressão de que mudar o mundo ao redor do player pode ser uma idéia melhor; quando é exatamente o oposto. Então aqui está a minha própria resposta ...
Ambas as opções podem funcionar, mas geralmente é uma má idéia "inverter a física" movendo o mundo ao redor do jogador, e não o jogador ao redor do mundo.
Perda / desperdício de desempenho:
O mundo normalmente terá muitos objetos; muitos, se não a maioria, estáticos ou adormecidos. O jogador terá um ou relativamente poucos objetos. Mover o mundo inteiro ao redor do jogador significa mover tudo na cena, exceto o jogador. Objetos estáticos, objetos dinâmicos adormecidos, objetos dinâmicos ativos, fontes de luz, fontes sonoras, etc; tudo tem que ser movido.
Isso é (obviamente) consideravelmente mais caro do que mover apenas o que realmente está em movimento (o jogador e talvez mais algumas coisas).
Manutenção e extensibilidade:
Mover o mundo ao redor do jogador faz com que o mundo (e tudo nele) seja o ponto em que as coisas estão acontecendo mais ativamente. Qualquer bug ou alteração no sistema significa que, potencialmente, tudo muda. Esta não é uma boa maneira de fazer as coisas; você deseja que os bugs / alterações sejam o mais isolados possível, para que você não tenha comportamentos inesperados em algum lugar em que não tenha feito alterações.
Há também muitos outros problemas com essa abordagem. Por exemplo, ele quebra muitas suposições de como as coisas devem funcionar no mecanismo. Você não seria capaz de usar dinâmico
RigidBody
para nada além do player, por exemplo; como um objeto com um anexoRigidBody
não definido como cinemático se comportará inesperadamente ao definir a posição / rotação / escala (o que você faria em todos os quadros, para cada objeto na cena, exceto o jogador 😨)Portanto, a resposta é apenas mover o jogador!
Bem ... sim e não . Como mencionado na resposta de Philipp, em um tipo de jogo de corredor infinito (ou qualquer jogo com uma grande área explorável contínua), ir muito longe da origem acabaria por introduzir FPPEs ( Erros de precisão de ponto flutuante) visíveis e, ainda mais, eventualmente, transbordar o tipo numérico, causando o travamento do jogo ou, basicamente, fazer com que o mundo do jogo fume de crack ... Em esteróides! Because (porque a essa altura, os FPPEs já tornariam o jogo no crack "normal")
A solução real :
Não faça nem faça os dois! Você deve manter o mundo estático e mover o jogador ao seu redor. Mas "re-enraíza" tanto o jogador quanto o mundo, quando o jogador começa a ficar muito longe da raiz (posição
[0, 0, 0]
) da cena.Se você mantiver a posição relativa das coisas (do jogador para o mundo ao seu redor) e fizer esse processo em uma única atualização de quadro, o jogador (real) nem perceberá!
Para fazer isso, você tem duas opções principais:
Aqui está um exemplo deste processo em ação
Mas, quão longe é longe demais?
Se você observar o código-fonte do Unity, eles usarão
1e-5
(0.00001
) como base para considerar dois valores de ponto flutuante "iguais", dentroVector2
eVector3
(os tipos de dados responsáveis pelas posições dos objetos, [euler-] rotações e escalas). Como a perda de precisão de ponto flutuante ocorre em ambos os sentidos do zero, é seguro assumir que qualquer coisa sob1e+5
(100000
) unidades de distância da cena raiz / origem é segura para trabalhar.Mas! Desde a...
... então provavelmente é uma boa ideia re-enraizar muito mais cedo / com mais frequência do que a marca de 100.000 unidades. O exemplo de vídeo que forneci parece ser feito a cada 1000 unidades, por exemplo.
fonte
Ambas as opções funcionam.
Mas se você quiser que o corredor interminável seja realmente interminável, precisará manter o jogador parado e mover o mundo. Caso contrário, você atingirá os limites das variáveis usadas para armazenar a posição X. Um número inteiro acabaria transbordando e uma variável de ponto flutuante se tornaria cada vez menos precisa, o que tornaria a jogabilidade mais lenta depois de um tempo. Mas você pode evitar esse problema usando um tipo grande o suficiente para que ninguém encontre esses problemas dentro do intervalo de tempo que se possa reproduzir em uma sessão (quando um jogador move 1000 pixels por segundo, um número inteiro de 32 bits transborda após 49 dias).
Faça o que parecer conceitualmente mais intuitivo para você.
fonte
Com base na resposta do XenoRo , em vez do método de re-root que eles descrevem, pode-se fazer o seguinte:
Crie um buffer circular de partes do seu mapa infinito gerado, pelas quais seu personagem se move com a posição atualizada com o módulo aritmético (para que você apenas rode o buffer circular). Comece substituindo partes do seu buffer assim que seu personagem sair do pedaço. A equação de atualização dos jogadores seria algo como:
player.position = (player.position + player.velocity) % worldBuffer.width;
Aqui está um exemplo pictórico do que estou falando:
Aqui está um exemplo do que acontece no acondicionamento no final.
Com esse método, você nunca se depara com erros de precisão, mas pode ser necessário criar um buffer muito grande se pretender fazer isso em 3d com uma distância de visão muito longa (pois você ainda precisará ver com antecedência) ) Se o tamanho do seu pedaço de pássaro flappy provavelmente for apenas o tamanho necessário para realizar uma única cena para uma única tela, e seu buffer poderá ser muito pequeno.
Observe que você começará a obter resultados repetidos com QUALQUER prng, e o número máximo de seqüências não repetitivas de uma geração PRNG é normalmente menor que o comprimento do pow (2, número de bits usado internamente), com merzenne twister, isso não é muito de um problema, pois usa 2,5k de estado interno, mas se você usar a variante minúscula, terá 2 ^ 127-1 iterações máximas antes de repetir (ou pior), ainda é um número astronomicamente grande . Você pode corrigir problemas de repetição de período, mesmo que o seu PRNG tenha um curto período por meio de boas funções de mistura de avalanches para a semente (à medida que você adiciona mais estado implicitamente) repetidamente.
fonte
Como já solicitado e aceito, realmente depende do escopo e do estilo do seu jogo, mas como não foi mencionado: o FlappyBird move o obstáculo pela tela, e não pelo jogador em todo o mundo.
Um criador está instanciando objetos fora da tela com uma velocidade fixa na
Vector2.left
direção.fonte