Estou tentando entender esse problema do Hello World-y no desenvolvimento de jogos. Eu criei um jogo TicTacToe no XNA, então acho que o próximo passo seria um clone do Breakout .
Lembre-se de que eu não tenho conhecimento de programação de jogos ou mesmo de que matemática devo aplicar para onde. É por isso que estou fazendo essa pergunta.
À pergunta: como posso determinar para onde a bola deve saltar quando atinge a raquete na parte inferior da tela?
Eu imagino que seria algo como:
- Capture a velocidade e o ângulo da bola recebida.
- Detecte onde tocou a barra (extrema esquerda, extrema direita, centro) e, de acordo com isso, aumente a velocidade se tocar as áreas externas.
- É aqui que estou preso. Ele Ele.
Alguma ideia? Sei que essa não é uma pergunta direta, mas tenho certeza de que é uma pergunta que todo mundo enfrenta em algum momento.
Estou lendo o livro Álgebra Linear recomendado neste site, mas ainda não tenho idéia se devo aplicá-lo aqui.
Respostas:
Aqui está a lógica relevante que usei no pong na minha página inicial : (por favor, jogue-a antes de ler, para que você saiba o efeito que estou conseguindo com o código a seguir)
Essencialmente, quando a bola colide com a raquete, sua direção é completamente desconsiderada; é dada uma nova direção de acordo com a distância do centro da raquete que colidiu. Se a bola acertar a raquete bem no centro, ela será enviada exatamente na horizontal; se atingir a borda, voa em um ângulo extremo (75 graus). E viaja sempre a uma velocidade constante.
Pegue o valor Y médio da raquete e subtraia a interseção Y da bola. Se a raquete tiver 10 pixels de altura, esse número estará entre -5 e 5. Eu chamo isso de "interseção relativa" porque agora está no "espaço da raquete", a interseção da bola em relação ao meio da raquete.
Pegue a interseção relativa e divida-a pela metade da altura da raquete. Agora nosso número de -5 a 5 é um decimal de -1 a 1; está normalizado . Em seguida, multiplique pelo ângulo máximo pelo qual você deseja que a bola salte. Defino-o como 5 * Pi / 12 radianos (75 graus).
Finalmente, calcule novas velocidades da bola, usando trigonometria simples.
Esse pode não ser o efeito que você está buscando ou também pode determinar uma velocidade multiplicando a interseção relativa normalizada por uma velocidade máxima; isso tornaria a bola mais rápida se acertar perto da borda de uma raquete ou mais lenta se acertar perto do centro.
Um vetor contém velocidade e direção, implicitamente. Eu armazeno meu vetor como "vx" e "vy"; isto é, a velocidade na direção x e a velocidade na direção y. Se você não fez um curso introdutório de física, isso pode parecer um pouco estranho para você.
A razão pela qual faço isso é porque reduz os cálculos por quadro necessários; cada quadro, você faz
x += vx * time;
ey += vy * time;
onde o tempo é o tempo desde o último quadro, em milissegundos (portanto, as velocidades são em pixels por milissegundo).Em relação à implementação da capacidade de curvar a bola:
Primeiro de tudo, você precisa saber a velocidade da raquete no momento em que a bola bate; o que significa que você precisa acompanhar o histórico da raquete, para poder conhecer uma ou mais posições anteriores da raquete, para poder compará-las à sua posição atual para ver se ela se moveu. (mudança de posição / mudança de tempo = velocidade; você precisa de 2 ou mais posições e os horários dessas posições)
Agora você também precisa rastrear uma velocidade angular da bola, que praticamente representa a curva ao longo da qual está viajando, mas é equivalente ao giro da bola no mundo real. Semelhante à maneira como você interpolava o ângulo de ressalto da posição relativa da bola em colisão com a raquete, também seria necessário interpolar essa velocidade angular (ou rotação) da velocidade da raquete em colisão. Em vez de simplesmente definir o giro como você faz com o ângulo de pulo, você pode adicionar ou subtrair o giro existente da bola, porque isso tende a funcionar bem nos jogos (o jogador pode perceber que a bola está girando e fazer com que ela gire ainda mais descontroladamente, ou contrarie o giro na tentativa de fazê-lo viajar reto).
Note, however, that while this is the most common sense and probably easiest way to implement it, the actual physics of a bounce doesn't rely solely on the velocity of the object it hits; an object with no angular velocity (no spin) which hits a surface at an angle, will have a spin imparted upon it. This might lead to a better game mechanic, so you may want to look into this, but I'm not certain of the physics behind it so I'm not going to try to explain it.
fonte
Já faz um tempo desde que eu fiz isso, mas acho que entendi direito.
Dada uma colisão perfeita, o ângulo de reflexão é igual ao ângulo de incidência.
Você conhece o normal de sua raquete (presumindo uma superfície plana): N Você conhece sua posição original da bola (no início do seu timestep): P Você conhece sua nova posição da bola (no final do timestep): P 'Você sabe o seu ponto de colisão: C Supondo que você calculou que o segmento P -> P' passa por sua raquete, sua nova posição refletida (P '') seria:
P '+ 2 * (N * (P' ponto-N))
A subexpressão N * (P 'ponto-N) calcula a profundidade ao longo do normal de colisão que a bola percorreu. O sinal de menos é corrigir o fato de que estamos verificando a profundidade oposta à direção do normal.
AP '+ 2 * a parte da subexpressão move a bola de volta acima do plano de colisão em 2 vezes a profundidade da colisão.
Se você deseja uma colisão menos que perfeita, altere o fator 2 para (1 + (1-k)), onde k é o seu coeficiente de atrito. Uma colisão perfeita tem um valor de k de 0, fazendo com que o ângulo de reflexão seja exatamente aquele do ângulo de entrada. Um valor de k igual a 1 causa uma colisão onde a bola fica na superfície do plano de colisão.
Seu novo vetor de velocidade, V '', a direção seria P '' - C. Normalize-o e multiplique pela sua velocidade de entrada e sua magnitude de velocidade resultante seria a mesma, mas na nova direção. Você pode usar essa velocidade multiplicando-a por um coeficiente, l, que aumentaria (l> 1) ou diminuiria (l <1) a velocidade resultante.
Para resumir:
P '' = P '+ (1-k) * (N * (P ponto-N)) V' '= l * V * ((P' '- C) / | P' '- C |)
Onde k e l são coeficientes de sua escolha.
fonte
A reflexão pode ser feita "correta" ou "fácil".
O caminho "certo" é calcular vetores perpendiculares às paredes. Em 2D, isso é muito fácil e você provavelmente poderia codificá-los com firmeza. Então, o passo de reflexão basicamente deixa intacto o componente "paralelo" do movimento e reverte o componente "perpendicular". Provavelmente, há informações detalhadas na Web para isso, talvez até no MathWorld.
A maneira "fácil" é simplesmente negar o movimento X ou Y quando você bate em uma parede. Se você acertar as paredes laterais, negaria X. Se você acertar o topo, nega Y. Se você quiser acelerar a bola, apenas aumente o que quiser; você pode acelerar na direção atual, multiplicando as velocidades X e Y ou pode acelerar apenas em um eixo.
fonte
Também estou fazendo um jogo arkanoid-ish e acho que a solução de como a bola deve se comportar ao acertar a raquete é muito mais simples e rápida do que entrar na abordagem sin / cos ... funciona bem para os propósitos de um jogo assim. Aqui está o que eu faço:
Obviamente, como a velocidade da bola aumenta com o tempo, interpolo as etapas x / y antes / depois para manter a detecção precisa de colisão, percorrendo todos os "stepX" e "stepY" que são calculados dividindo cada componente de velocidade pelo módulo do vetor formado pelas posições atuais e futuras da bola.
Se ocorrer uma colisão contra a raquete, divido a velocidade Y por 20. Esse "20" é o valor mais conveniente que obtive para obter o ângulo máximo resultante quando a bola bate nos lados da raquete, mas você pode alterá-la para qualquer suas necessidades são, apenas brinque com alguns valores e escolha o melhor para você. Ao dividir, digamos uma velocidade de 5, que é a minha velocidade inicial de jogo por esse número (20), recebo um "fator de rebote" de 0,25. Este cálculo mantém meus ângulos bastante proporcionais quando a velocidade aumenta no tempo até o meu valor máximo de velocidade que, por exemplo, pode ser 15 (nesse caso: 15/20 = 0,75). Considerando que minhas cordas de raquete x, y são de mão média (x e y representam o centro da raquete), multiplico esse resultado pela diferença entre a posição da bola e a posição da raquete. Quanto maior a diferença, o greatear o ângulo resultante. Além disso, usando uma raquete de mão média, você obtém o sinal correto para o incremento de x, dependendo do lado que a bola bate sem ter que se preocupar em calcular o centro. No pseudo-código:
Para n = 0 ao módulo ...
se for detectada uma colisão, speedX = - (speedY / 20) * (paddleX - ballX); speedY = -speedY;
Saída; fim se
...
x = x + passoX; y = y + passoY;
fim para
Lembre-se, sempre tente manter as coisas SIMPLES. Espero que ajude!
fonte
A raquete no Breakout, quando segue o estilo que você está descrevendo, geralmente é modelada como uma superfície curva. O ângulo de incidência muda de acordo com o local da raquete. No ponto morto, a linha tangente à curva é absolutamente horizontal e a bola reflete como esperado. À medida que você se move para fora do centro, a tangente à curva torna-se cada vez mais angulada, e a bola reflete diferentemente como resultado.
O ponto principal é que o ângulo de reflexão, não a velocidade da bola, é o que muda. A velocidade da bola geralmente aumenta lentamente ao longo do tempo.
fonte
angle = 1 - 2 * (ball.x - paddle.left) / paddle.width
fornecerá um número entre 1 e -1; isto (vezes que algum valor foi ajustado para a mecânica do jogo) é a inclinação da linha tangente no ponto em que a bola colidiu. Reflita sobre essa linha em vez da estritamente horizontal.Nolan Bushnell fez uma palestra no SIEGE no fim de semana passado e falou sobre um problema semelhante com o pong original. Você não precisa fazer muitos cálculos complicados. Se você acertar a parte esquerda do painel, envie a bola para a esquerda. Faça o mesmo para o lado direito.
Para começar, você pode fazer o ângulo para os lados esquerdo e direito 45 graus. Depois de terminar o jogo, você pode se quiser voltar e tornar isso mais complicado, mas faça o mais simples possível.
fonte
Breakout é um trabalho clássico para iniciantes para começar a mergulhar no mundo da programação de jogos baseada na física. Basicamente, a bola tem um movimento de salto quando bate na parede. Como alguém acima sugeriu, o ângulo de incidência é igual ao ângulo de reflexão. Mas quando você considera a bola bater na raquete. A lógica é dividida em 3 seções. 1.) A bola bate na parte central da raquete. 2.) A bola bate na parte esquerda da raquete. 3.) A bola bate na posição direita da raquete.
Quando você considera a parte central: Você não precisa diferenciar o efeito de ressalto do que é aplicado ao bater na bola. A bola é desviada normalmente. Mas, quando qualquer direção é atingida, o caso é diferente.
Quando a bola é atingida no lado esquerdo, ou seja, considere a bola vinda do lado esquerdo da tela e você está vindo com a raquete do lado direito. Então, quando você bate na bola com a parte esquerda, a bola deve refletir a direção de onde veio, ou seja, com o mesmo ângulo de onde veio. Mesmo é o caso vice-versa. Na parte direita também se aplica a mesma coisa.
Esse movimento da bola em direção à esquerda ou à direita quando está sendo atingido a torna mais crível.
Espero que você tenha entendido a ideia, pelo menos em termos de lógica.
fonte
Imagine que você calcula a distância entre o centro da raquete e o ponto em que a bola Y bate e a chama
d
. Vamos supor qued
tenha um valor positivo quando a bola bater acima do centro da raquete. Agora você pode adicionard * -0.1
à velocidade Y da sua bola e ela começará a mudar de direção. Aqui está um exemplo em javascript que pode ser facilmente traduzido em c #!fonte
isso ajudará http://www-classes.usc.edu/engr/ee-s/477p/s00/pong.html a simplesmente inverter xey dependendo de onde ele atinge a tela. se está subindo e atinge o topo, inverte a velocidade y, mantendo a velocidade x
fonte
Oi Eu fui recentemente tentado fazer um jogo de bola e descobri uma solução para isso. Então o que eu fiz: a raquete está se movendo enquanto jogamos o jogo. Meu sistema de coordenadas é deixado como está, o ponto superior esquerdo da tela é 0,0. A raquete está se movendo neste sistema de coordenadas. O eixo x aponta de 0 para a largura da tela e o eixo y está apontando para 0 para a altura da tela. Criei uma raquete com tamanho fixo 100 de largura e 20 de altura. E então eu desenho um círculo imaginário ao redor dele. Quando a bola bate na raquete, eu calculo o ponto central da raquete
Então, subtraio o centro da posição atual da bola, para que o sistema de coordenadas fique no centro da raquete, ballCenter é o ponto em que a bola bate na raquete (- (largura da raquete + r) .. 0 .. (largura da raquete + r )) isso nada mais é do que redimensionar o ponto de batida na raquete
calcular o ponto de interseção do círculo com a ajuda do ponto de acerto da bola (x0), isso é uma recomputação; pedimos a coordenada y no círculo com a coordenada x0 já conhecida e foi necessário um giro para o eixo y
Calcule a derivada da equação normal do círculo que é definida ao redor da raquete com pá de raioRadius f (x, y) = x ^ 2 + y ^ 2-r ^ 2
normalizar o vetor N, para obter um vetor unitário para a superfície normal
agora temos as normais de superfície normalizadas (unitárias) para o remo. Calcule a nova direção com essas normais de superfície, isso será calculado com a ajuda da fórmula do vetor de reflexão: new_direction = old_direction-2 * ponto (N, old_direction) * N, mas, em vez disso, com a superfície normal apontando sempre para cima, a normal será estar mudando de ponto a ponto onde a bola bate na raquete
Publiquei minha solução para esse problema. Para mais detalhes e para o jogo completo, você pode ver meu repositório no github:
https://github.com/zoli333/BricksGame
escrito em java com eclipse. Existe outra solução para isso comentada em Ball.java, onde o redimensionamento não ocorre. Não movo o sistema de coordenadas de coordenadas para o ponto central da raquete, em vez disso, calculo tudo isso a partir do sistema de coordenadas topleft 0,0 em relação a o ponto central da raquete. Isso também funciona.
fonte