Implementação de transmissão em um jogo de carro

23

Estou tentando criar um jogo de carro simples com mudanças manuais de marchas. No entanto, estou com problemas para implementar as mudanças de velocidade.

Aqui está o meu código atual para o "carro":

int gear = 1; // Current gear, initially the 1st
int gearCount = 5; // Total no. of gears

int speed = 0; // Speed (km/h), initially 0
int[] maxSpeedsPerGear = new int[]
{
    40,  // First gear max. speed at max. RPM
    70,  // Second gear max. speed at max. RPM
    100, // and so on
    130,
    170
}

int rpm = 0; // Current engine RPM
int maxRPM = 8500; // Max. RPM

public void update(float dt)
{
    if(rpm < maxRPM)
    {
        rpm += 65 / gear; // The higher the gear, the slower the RPM increases
    }

    speed = (int) ((float)rpm / (float)maxRPM) * (float)maxSpeedsPerGear[gear - 1]);

    if(isKeyPressed(Keys.SPACE))
    {
        if(gear < gearCount)
        {
            gear++; // Change the gear
            rpm -= 3600; // Drop the RPM by a fixed amount
            if(rpm < 1500) rpm = 1500; // Just a silly "lower limit" for RPM
        }
    }
}

No entanto, essa implementação realmente não funciona. A primeira marcha funciona bem, mas as seguintes mudanças de marcha causam queda de velocidade. Ao adicionar algumas mensagens de depuração, obtenho esses valores de velocidade ao alterar no limite de RPM:

Speed at gear 1 before change: 40
Speed after changing from gear 1 to gear 2: 41

Speed at gear 2 before change: 70
Speed after changing from gear 2 to gear 3: 59

Speed at gear 3 before change: 100
Speed after changing from gear 3 to gear 4: 76

Speed at gear 4 before change: 130
Speed after changing from gear 4 to gear 5: 100

Como você pode ver, a velocidade após cada alteração é mais lenta antes da alteração. Como você levaria em consideração a velocidade antes da mudança de marcha, para que a velocidade não caísse ao trocar de marcha?

manabreak
fonte
1
Lembro-me deste excelente tutorial detalhado: Física do carro para jogos . Cerca de um terço do artigo começa a falar sobre a transmissão de força do motor.
Eric

Respostas:

17

Calcule a nova RPM com base na nova marcha e velocidade atual do carro.

speed = (int) ((float)rpm / (float)maxRPM) * (float)maxSpeedsPerGear[gear - 1]);

so: em vez de:

rpm -= 3600; // Drop the RPM by a fixed amount

usar:

rpm = max(maxRPM,(float)maxRPM * (float)speed / (float)maxSpeedsPerGear[gear - 1]);

A velocidade agora será a mesma antes e depois da troca de marchas, e você poderá acelerar / desacelerar a partir daí.

editar: adicionado max(maxRPM, calc)como você deseja limitá-lo. Como em um carro, isso deve resultar em uma perda repentina de velocidade

Baldrickk
fonte
29

isso ocorre porque não há inércia no seu cálculo de velocidade. você apenas calcula isso como uma consequência absoluta das rotações e rotações do motor. mas quando você calcula a nova rpm após a troca de marchas, você a reduz empiricamente em etapas fixas de 3600 rpm.

Este é o seu erro. o número de rotações por minuto não é fixo entre as marchas. você pode corrigi-lo criando uma segunda matriz armazenando o número exato de queda de rpm entre cada engrenagem.

A segunda maneira de corrigi-lo é usando cálculos físicos. Você está fazendo uma simulação, para poder fazer uma integração numérica. Usando tempo, dte integração de euler ou integração de Verlet. Isso parece complexo com nomes e tudo, mas na verdade não é.

Basicamente, isso significa que você cria uma tabela de pesquisa para o torque do motor em determinadas rotações. Então você levaria em consideração alguma resistência do ar aumentando com o quadrado da velocidade. Então a simulação calcularia a próxima velocidade revertendo a segunda lei dos newtons f=m a.
Para encontrar a=f/m, em seguida, a integração Euler: speed=speed+a*dt. o mé cerca de 1200 (peso típico do carro).fé a força derivada do torque do motor, reduzida na caixa de velocidades e, em seguida, convertida em força usando a fórmula da alavanca, considerando o raio da roda. (um produto vetorial cruzado geralmente, mas pode ser simplificado pela multiplicação do torque com raio. porque netwton / metros multiplicou metros = newtons.)

Dessa forma, a rotação do motor é calculada para trás, em função da velocidade linear do carro.

v.oddou
fonte
2
Não existe exact number of RPM drop between each gear. É uma proporção, como @Baldrickk aponta. E embora seja uma ótima idéia fazer com que a saída da transmissão seja mais torque do que velocidade, uma discussão sobre resistência ao vento e integração de verlet está um pouco fora do escopo da questão, não?
287 Justin
Sim. para um ponto na resposta à pergunta, eu recomendaria a resposta de Baldrickk. Eu votei nele.
v.oddou
5

As engrenagens são usadas como um mecanismo de redução.

Usando uma transmissão simplificada com apenas duas relações na caixa de velocidades, uma engrenagem de entrada (o motor) e uma engrenagem de saída (uma das relações da caixa de velocidades), temos duas relações de redução diferentes.

Portanto, para uma engrenagem de entrada com x dentes e uma engrenagem de saída de x / 2 dentes, a velocidade da engrenagem de saída é duas vezes a velocidade da engrenagem de entrada (uma proporção de dois para um)

rpm2 = rpm1 * gearRatio

Onde:

gearRatio = teeth1 / teeth2

Portanto, em vez de limitar cada marcha pela velocidade codificada, podemos limitá-lo pela proporção. Você pode calcular a velocidade de um par específico (rpmEngine, gear) e, quando a mudança é alterada, calcular a velocidade do motor, dada a velocidade conhecida e um novo par.

Para simplificar, use apenas um motor conectado a duas marchas:

rpmEngine = 5000

gearRatio[1] = 2 #low gear:  one rotation of the engine results in 2 rotations output
gearRatio[2] = 3 #high gear: one rotation of the engine results in 3 rotations output

vehicleSpeed = rpmEngine * gearRatio[selectedGear]

então:

selectedGear = 1
vehicleSpeed = rpmEngine * gearRatio[selectedGear] #5000 * 2 = 10000 

ao mudar para a segunda marcha, 10000 é a velocidade, portanto, conectando-o à mesma fórmula, agora temos:

vehicleSpeed = 10000 #computed above
selectedGear = 2

assim nossa nova rpm:

rpmEngine = vehicleSpeed / gearRatio[selectedGear] #10000 / 3 = 3333.3

Esses 10000 seriam reduzidos ainda mais por um diferencial (que pode ser abstraído como apenas outra engrenagem, procure se necessário, desculpe, pode postar apenas dois links) e, em seguida, pelo tamanho da roda para calcular a velocidade do solo em quilômetros ou milhas por hora .

Você deve levar em consideração o fato de que a mudança para uma marcha mais baixa aumenta a rotação do motor; portanto, uma abordagem simples é verificar a maxRPM e limitar a rotação após a mudança para a rotação máxima, reduzindo assim a velocidade do veículo.

Então, basicamente, toda vez que ocorre uma troca de marchas, você calcula a rotação do motor a partir da velocidade do veículo, limita-a por maxRPM e volta ao "normal" onde atualiza a rotação da entrada do usuário e calcula a velocidade com base nisso.

Para uma simulação realista, você deve levar em consideração pelo menos o torque do motor (resposta de v.oddou) e a derrapagem da embreagem, que combinados teriam os seguintes efeitos: - ao mudar de marcha, assumindo que a mudança seja rápida o suficiente para que a rotação do motor não caia , a velocidade será aumentada enquanto a rotação do motor for reduzida até que sejam equilibradas - ao reduzir, a velocidade do veículo será reduzida até que o motor seja elevado para a nova rotação, mas isso provavelmente vai além da implementação "simples".

cristiancrc
fonte
4

Lembre-se de que uma transmissão manual acoplada é um dispositivo de mão dupla. O motor pode acelerar o veículo, assim como o veículo (mais especificamente seu momento) pode acelerar o motor.

Este foi um problema real nas primeiras transmissões manuais. A redução de marcha aumentaria repentinamente o motor a uma rotação mais alta, jogando os ciclos de ignição fora de sincronia e possivelmente causando a parada do motor. Isso foi compensado pela condução especializada, onde o motorista teve que acelerar o motor para a velocidade correta antes de liberar a embreagem para acionar a transmissão.

Isso foi até a sincronização foi desenvolvida. É um mecanismo que impede que a transmissão seja ativada até que as velocidades de entrada e saída estejam sincronizadas.

Então, o que eu sugiro é que você emule a sincronização e não ative a transmissão até que a rotação do motor e a velocidade do carro correspondam aos níveis atuais.

edgerunner
fonte
2

A resposta existente parece complexa demais. Para um jogo, o RPM é apenas um indicador na tela. A velocidade real é a variável real. A relação de transmissão determina como você converte a velocidade do motor em RPMs. Mudar de marcha altera a proporção, mas não a velocidade. Obviamente, o RPM também muda conforme o inverso da relação de transmissão.

Overrevving (downshifting além do seu limite de 8500 RPM) é algo que você implementaria separadamente, mas é uma coisa ruim nos carros e você pode deixar que isso seja ruim no seu jogo.

MSalters
fonte
2
A resposta existente é exatamente o que a maioria dos jogos que eu já vi fazer, mesmo jogos simples de arcade, porque realmente não é tão complexo. RPM na tela pode ser apenas um número, mas essa abordagem dá-lhe tanto o número (que você pode ajustar para os indicadores visuais de qualquer maneira), eo comportamento para combinar esses números
Selali Adobor
2

Como outros já mencionaram, a velocidade do veículo deve ser o valor real e a RPM deve ser derivada disso. A mudança de marcha deve fazer com que a velocidade de rotação de um motor diminua, porque a proporção de RPM por km / h "muda instantaneamente", mas a velocidade do veículo não.

Sugiro, no entanto, que o torque do motor aumente com as RPM até um certo limite e ultrapasse esse limite. A taxa na qual um veículo acelera deve ser proporcional ao torque dividido pela relação de transmissão, menos o arrasto de ar que é proporcional ao quadrado da velocidade. Se as marchas consecutivas tiverem uma proporção de 1: 41: 1, ocorrerá uma mudança ideal para aceleração no ponto em que o torque na marcha mais baixa caiu para cerca de 70% do que seria na próxima marcha mais alta.

supercat
fonte
2

Com base em @ v.oddou, usando

max(maxRPM, calc)

faria com que o RPMS chegasse ao máximo instantaneamente quando as marchas fossem trocadas, não permitindo uma transição suave de uma engrenagem para outra. A maneira correta seria resolver as RPMs usando a variável de velocidade como uma equação.

speed = (int) ((float)rpm / (float)maxRPM) * (float)maxSpeedsPerGear[gear - 1]);

Resolva para rpm

rpm = (maxRPM * speed) / maxSpeedsPerGear[gear - 1] ;

como a marcha é 1 mais alta do que era antes, as RPMs serão mais baixas.

White Development Studios
fonte