Quero fazer uma série de padrões de marcadores em expansão que formam formas como quadrados, triângulos etc. estrela em expansão:
Quero fazer uma série de padrões de marcadores em expansão que formam formas como quadrados, triângulos etc. estrela em expansão:
Respostas:
A maneira mais fácil de fazer isso seria primeiro projetar a forma e depois calcular o movimento das partículas. Nesta resposta, estarei construindo um quadrado, mas isso se aplica a qualquer forma.
Comece projetando sua forma como posições relativas em torno de algum ponto de origem.
Agora você precisa calcular como a forma será expandida. Para fazer isso, simplesmente calculamos o vetor apontando de origin
para todos point
subtraindo a origin
posição da posição de nossa point
e normalizando o vetor. vector = normalize(point.x - origin.x, point.y - origin.y)
.
Agora podemos calcular a posição dos pontos a qualquer momento usando esse vetor. Você calcula a próxima posição dos pontos fazendo point.position += point.vector * point.velocity
. Exemplo de pseudocódigo usando nosso ponto anterior:
// When you start your program you set these values.
point.position = (-3, 3); // Start position. Can be anything.
point.vector = normalize(-3, 3); // Normalized vector.
point.velocity = 3; // Can be anything.
// You do this calculation every frame.
point.position += point.vector * point.velocity;
// point.vector * point.velocity = (-3, 3)
// point.position is now (-6, 6) since (-3, 3) + (-3, 3) = (-6, 6)
Isso moverá todos os pontos para fora em 3 unidades a cada quadro.
Notas
Portanto, existe um projeto chamado BulletML, que é uma linguagem de marcação para criar padrões complexos de partículas / marcadores. Você quase certamente precisará portar o código para o seu próprio idioma, mas ele pode fazer coisas realmente incríveis.
Por exemplo, esse chefe foi feito em uma extensão (fortemente modificada) do BulletML for Unity3D (o autor desse padrão enviou esse vídeo e Misery é insano, além de bom 1 ). É a variação mais difícil desse inimigo e mostra o que o BulletML é capaz de fazer muito bem (e confira alguns dos outros chefes de Misery também, como o Wallmaster ).
Ou posso mostrar este exemplo, que é um padrão que escrevi enquanto trabalhava em uma expansão para The Last Federation , usando uma revisão mais antiga do sistema que é menos amigável ao mod e usa apenas variáveis AZ de um único caractere:
As balas verdes que produzem esses anéis são geradas por uma bala-mãe que gira em alta velocidade, mas elas não têm movimento. Eles causam dano massivo, mantendo o jogador a uma distância maior, restringindo-o a armas com menos danos e permitindo que defensores móveis assediem o jogador (o jogador venceu se a estrutura imóvel no meio fosse destruída).
Aqui está uma parte da sintaxe XML que cria essas bolhas:
<bullet_pattern name="Barrier">
$WallShotAngle B=.3 A=90
$WallShotAngle B=.3 A=-90
$WallShotAngle B=.3 A=0
$WallShotAngle B=.375 A=180
</bullet_pattern>
<var name="WallShotAngle">
<bullet angle="[A]" speed="4000" interval_mult=".01" dumbfire="1" shot_type="GravityWavePurple">
<wait time="[B]" />
<change angle="0" speed="1000" time=".0001" />
<spawn>
<bullet_pattern>
<bullet angle="[A]" speed="0" shot_type="CurveBarGreen" damage_mult="8">
<wait time="12" />
<die />
</bullet>
</bullet_pattern>
</spawn>
<die />
</bullet>
</var>
Você pode ver alguns dos tiros roxos de "onda de gravidade" na captura de tela, que viajam quase instantaneamente da fonte (que gira) até a borda da bolha, e então gera o tiro verde de "barra curvada", que fica lá por 12 segundos antes desaparecendo. Os tiros azuis e amarelos que eu omiti, pois são muito mais complicados.
Um dos outros padrões (um projétil de artilharia ) na expansão foi realmente escrito por Misery, embora eu tenha feito algumas modificações. Inicialmente, é um tiro penetrante de baixo dano que voa a longo alcance e depois explode em uma enorme queima de fogos, causando muitos danos. Seu alcance máximo era muito maior do que o jogador poderia alcançar, forçando essencialmente o jogador a se envolver em curto alcance, o que foi vantajoso para os outros tipos de unidades de NPC devido ao efeito de espingarda (mais balas agrupadas em uma pequena zona).
O BulletML é fácil de trabalhar, geralmente, e pode fazer coisas incríveis. Os marcadores podem mudar de direção, mudar de velocidade, gerar outros padrões, morrer cedo, repetir a coleta de comandos em um loop, usar atrasos, alterar a imagem de sprite de bala, seguir o pai (ou não) ... E qualquer coisa que ele não suporte escreva nele.
Definitivamente, eu recomendaria se você estivesse fazendo um jogo de tiro sério. Você ainda precisaria calcular a matemática das coordenadas para obter as formas desejadas, como Charanor fala em sua resposta, mas um mecanismo de bala como o BulletML lhe dará muito mais flexibilidade que você gastará mais tempo projetando novos padrões do que descobrir como codificá-los.
Conforme indicado por Charanor, você pode usar uma matriz de pontos para definir sua forma e, em seguida, atualizar sua posição ao longo do tempo. Abaixo está um exemplo prático de como implementar uma forma de estrela ou uma forma personalizada usando pontos:
package com.mygdx.gtest;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
public class Test extends ApplicationAdapter{
public SpriteBatch sb;
private StarShape ss, ssBig;
@Override
public void create() {
sb = new SpriteBatch();
Pixmap pmap = new Pixmap(2, 2,Format.RGBA8888);
pmap.setColor(Color.WHITE);
pmap.fill();
ss = new StarShape(50,50,new Texture(pmap), 10, true);
ssBig = new StarShape(250,250,new Texture(pmap), 50, false);
pmap.dispose();
}
@Override
public void render() {
super.render();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
ss.update(Gdx.graphics.getDeltaTime());
ssBig.update(Gdx.graphics.getDeltaTime());
sb.begin();
ss.draw(sb);
ssBig.draw(sb);
sb.end();
}
@Override
public void dispose() {
super.dispose();
}
private class StarShape{
public float progress = 1f;
public Texture bulletTex;
public Array<Vector2> points = new Array<Vector2>();
public Vector2 center;
public StarShape(float x, float y, Texture tex, float initialSize, boolean mathWay){
center = new Vector2(x,y);
bulletTex = tex;
if(mathWay){
// define star shape with maths
float alpha = (float)(2 * Math.PI) / 10;
float radius = initialSize;
for(int i = 11; i != 0; i--){
float r = radius*(i % 2 + 1)/2;
float omega = alpha * i;
points.add(
new Vector2(
(float)(r * Math.sin(omega)),
(float)(r * Math.cos(omega))
)
);
}
}else{
// or define star shape manually (better for non geometric shapes etc
//define circle
points.add(new Vector2(-3f,0f));
points.add(new Vector2(-2.8f,1f));
points.add(new Vector2(-2.2f,2.2f));
points.add(new Vector2(-1f,2.8f));
points.add(new Vector2(0f,3f));
points.add(new Vector2(1f,2.8f));
points.add(new Vector2(2.2f,2.2f));
points.add(new Vector2(2.8f,1f));
points.add(new Vector2(3f,0f));
points.add(new Vector2(2.8f,-1f));
points.add(new Vector2(2.2f,-2.2f));
points.add(new Vector2(1f,-2.8f));
points.add(new Vector2(0f,-3f));
points.add(new Vector2(-1f,-2.8f));
points.add(new Vector2(-2.2f,-2.2f));
points.add(new Vector2(-2.8f,-1f));
// mouth
points.add(new Vector2(-2,-1));
points.add(new Vector2(-1,-1));
points.add(new Vector2(0,-1));
points.add(new Vector2(1,-1));
points.add(new Vector2(2,-1));
points.add(new Vector2(-1.5f,-1.1f));
points.add(new Vector2(-1,-2));
points.add(new Vector2(0,-2.2f));
points.add(new Vector2(1,-2));
points.add(new Vector2(1.5f,-1.1f));
points.add(new Vector2(-1.5f,1.5f));
points.add(new Vector2(1.5f,1.5f));
}
}
public void update(float deltaTime){
this.progress+= deltaTime;
}
public void draw(SpriteBatch sb){
Vector2 temp = new Vector2(0,0);
for(Vector2 point: points){
temp.x = (point.x);
temp.y = (point.y);
temp.scl(progress);
sb.draw(bulletTex,temp.x + center.x,temp.y +center.y);
}
}
}
}