Automatyczne hamowanie silnika - Symulator Samochodu

0

Dzień dobry,

Jestem w trakcie pisania pierwszego projektu, jest to symulator samochodu (biegi, predkosc, obroty i wlacz/wylacz). Problem mój polega na tym, że nie wiem jak włączyć do tego wszystkiego automatyczne hamowanie silnikiem. Mianowicie, chciałbym:
-gdy mam na biegu "N", tzw. luzie, i dodam gazu (obroty się podniosą) i go puszcze, to chciałbym aby te obroty same opadały, z jakimś tam czasem.
-gdy mam na biegu innym niż N, to chciałbym aby predkosc oraz odbroty się zmniejszały, aż obroty będą posiadały wartość X.

mój kod wygląda następująco:

import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class SamSymulator extends JPanel {
	private static final long serialVersionUID = 1L;
	double predkosc;
	int obroty = 0;
	int bieg = 0;
	boolean silnikOdpalony = false;
	private JTextField txtPredkosc;
	private JTextField txtBieg;
	private JTextField txtObroty;
	private JTextField txtDeska;

	public SamSymulator() throws InterruptedException {
		setBackground(Color.LIGHT_GRAY);
		setLayout(null);

		JLabel lblPredkosc = new JLabel("Predkosc:");
		lblPredkosc.setHorizontalAlignment(SwingConstants.RIGHT);
		lblPredkosc.setBounds(136, 28, 68, 14);
		add(lblPredkosc);

		JLabel lblBieg = new JLabel("Bieg:");
		lblBieg.setHorizontalAlignment(SwingConstants.RIGHT);
		lblBieg.setBounds(134, 58, 68, 14);
		add(lblBieg);

		JLabel lblObroty = new JLabel("Obroty:");
		lblObroty.setHorizontalAlignment(SwingConstants.RIGHT);
		lblObroty.setBounds(136, 90, 68, 14);
		add(lblObroty);

		txtPredkosc = new JTextField();
		txtPredkosc.setText("0");
		txtPredkosc.setHorizontalAlignment(SwingConstants.CENTER);
		txtPredkosc.setColumns(10);
		txtPredkosc.setBounds(214, 25, 86, 20);
		txtPredkosc.setEditable(false);
		add(txtPredkosc);

		txtBieg = new JTextField();
		txtBieg.setText("P");
		txtBieg.setHorizontalAlignment(SwingConstants.CENTER);
		txtBieg.setColumns(10);
		txtBieg.setBounds(214, 56, 86, 20);
		txtBieg.setEditable(false);
		add(txtBieg);

		txtObroty = new JTextField();
		txtObroty.setText("0");
		txtObroty.setHorizontalAlignment(SwingConstants.CENTER);
		txtObroty.setColumns(10);
		txtObroty.setBounds(214, 87, 86, 20);
		txtObroty.setEditable(false);
		add(txtObroty);

		JButton btnStart = new JButton("START");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JButton btn = (JButton) e.getSource();
				if (btn.getText().equals("STOP")) {
					obroty = 0;
					predkosc = 0;
					txtObroty.setText(String.valueOf(obroty));
					txtPredkosc.setText(String.valueOf(predkosc));
					txtBieg.setText("P");
					bieg = 0;
					btn.setText("START");
					silnikOdpalony = false;
					txtDeska.setText("SILNIK ZOSTAL ZGASZONY");
				} else {
					obroty = 10;
					txtObroty.setText(String.valueOf(obroty));
					txtBieg.setText("N");
					bieg = 0;
					btn.setText("STOP");
					silnikOdpalony = true;
					txtDeska.setText("SILNIK ZOSTAL ODPALONY");
					btn.requestFocus();
				}
			}
		});

		txtDeska = new JTextField();
		txtDeska.setText("WCISNIJ START, ABY ODPALIC SILNIK");
		txtDeska.setHorizontalAlignment(SwingConstants.CENTER);
		txtDeska.setEditable(false);
		txtDeska.setBounds(111, 115, 246, 36);
		add(txtDeska);
		txtDeska.setColumns(10);
		btnStart.setBounds(111, 183, 135, 70);
		add(btnStart);

		JButton btnBiegGora = new JButton("Bieg GORA");
		btnBiegGora.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (bieg < 6) {
					if (obroty < 20 && bieg >= 1) {
						txtDeska.setText("ZA MALE OBROTY, BY ZWIEKSZYC BIEG");
					} else {
						bieg++;
						if (bieg == 0) {
							txtBieg.setText("N");
							obroty = 10;
							predkosc = 0;
							txtPredkosc.setText(Double.toString(getPredkosc()));
						} else if (bieg == 1) {
							obroty = 10;
							predkosc = 5;
							txtPredkosc.setText(Double.toString(getPredkosc()));
							txtBieg.setText(Integer.toString(bieg));
						} else {
							txtBieg.setText(Integer.toString(bieg));
							obroty = obroty - 10;
						}
						txtObroty.setText(Integer.toString(getObroty()));
						txtDeska.setText("");
					}
				}
				btnStart.requestFocus();
			}
		});
		btnBiegGora.setBounds(268, 183, 89, 23);
		add(btnBiegGora);

		JButton btnBiegDol = new JButton("Bieg DOL");
		btnBiegDol.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (bieg > -1) {
					if (obroty > 40 && bieg > 1) {
						txtDeska.setText("ZA DUZE OBROTY, BY ZMNIEJSZYC BIEG");
					} else {
						bieg--;
						if (bieg == 0) {
							txtBieg.setText("N");
							obroty = 10;
							predkosc = 0;
							txtPredkosc.setText(Double.toString(getPredkosc()));
						} else if (bieg == -1) {
							txtBieg.setText("R");
							obroty = 10;
							predkosc = 5;
							txtPredkosc.setText(Double.toString(getPredkosc()));
						} else {
							txtBieg.setText(Integer.toString(bieg));
							obroty = obroty + 10;
						}
						txtObroty.setText(Integer.toString(getObroty()));
						txtDeska.setText("");
					}
				}
				btnStart.requestFocus();
			}
		});
		btnBiegDol.setBounds(268, 229, 89, 23);
		add(btnBiegDol);

		JLabel lblInstrukcja = new JLabel("Instrukcja");
		lblInstrukcja.setBounds(27, 11, 55, 14);
		add(lblInstrukcja);
		btnStart.addKeyListener(new SpeedListener());
	}

	public class SpeedListener implements KeyListener, ActionListener {
		@Override
		public void keyPressed(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_W) {
				gaz();

			}
			if (e.getKeyCode() == KeyEvent.VK_S) {
				hamulec();
			}
		}

		@Override
		public void keyReleased(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_W) {
			}
		}

		@Override
		public void keyTyped(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void actionPerformed(ActionEvent e) {
		}
	}

	public void gaz() {
		int biegObrot;
		if (silnikOdpalony) {
			if (bieg > 1) {
				if (obroty < 70) {
					obroty++;
					txtObroty.setText(Integer.toString(getObroty()));
					biegObrot = obroty + (10 * bieg) - 17;
					predkosc = 1.5 * biegObrot;
					txtPredkosc.setText(Double.toString(getPredkosc()));
					if (obroty > 25)
						txtDeska.setText("WRZUC WYZSZY BIEG");
					else
						txtDeska.setText("");
				}
			} else if (bieg == 1) {
				if (obroty < 70) {
					obroty++;
					txtObroty.setText(Integer.toString(getObroty()));
					biegObrot = obroty + (10 * bieg) - 17;
					predkosc = 1.5 * biegObrot;
					txtPredkosc.setText(Double.toString(getPredkosc()));
					if (obroty > 25)
						txtDeska.setText("WRZUC WYZSZY BIEG");
					else
						txtDeska.setText("");
				}
			} else if (bieg == -1) {
				if (obroty < 70) {
					obroty++;
					txtObroty.setText(Integer.toString(getObroty()));
					biegObrot = obroty - 7;
					predkosc = 0.5 * biegObrot;
					txtPredkosc.setText(Double.toString(getPredkosc()));
				}
			} else {
				if (obroty < 70) {
					obroty++;
					txtObroty.setText(Integer.toString(getObroty()));
					if (obroty > 25)
						txtDeska.setText("WRZUC BIEG, ZEBY ZACZAC JECHAC");
				}
			}
		}
	}

	public void hamulec() {
		int biegObrot;
		if (silnikOdpalony) {
			if (bieg > 0) {
				if (obroty > 10) {
					obroty--;
					txtObroty.setText(Integer.toString(getObroty()));
					biegObrot = obroty + (10 * bieg) - 17;
					predkosc = 1.5 * biegObrot;
					txtPredkosc.setText(Double.toString(getPredkosc()));
					if (obroty < 15)
						txtDeska.setText("WRZUC NIZSZY BIEG");
					else
						txtDeska.setText("");
				}
			}
			if (bieg == -1) {
				if (obroty > 10) {
					obroty--;
					txtObroty.setText(Integer.toString(getObroty()));
					biegObrot = obroty - 7;
					predkosc = 0.5 * biegObrot;
					txtPredkosc.setText(Double.toString(getPredkosc()));
				}
			}
		}
	}


	public double getPredkosc() {
		return predkosc;
	}

	public int getObroty() {
		return obroty;
	}
}

Pozdrawiam!

2

Powinieneś to zrobić trochę inaczej. Dodawanie gazu jest zależne od prędkości procesora. Na wolnym komputerze dodawać się będzie wolniej niż na szybkim. Musisz to uzależnić od czasu.
Zrób sobie pętle, w której będziesz sprawdzał ile upłynęło czasu pomiędzy wykonaniami. Jeśli sobie ustalisz np 60fps to oznacza, że pomiędzy klatkami musiało upłynąć 16ms. Jeśli upłynęło to robisz operację (np gaz, jeśli nie to nic nie robisz i puszczasz pętle jeszcze raz). To taki uproszczony mechanizm. Dzięki temu będziesz mógł zaimplementować sobie spadek obrotów jeśli gaz nie jest wciśnięty, a nawet dostosować prędkość spadania obrotów.

Jeśli chodzi o obsługę przycisków to musisz to robić synchronicznie. To znaczy, sprawdzasz programistycznie isPressed na JButton wewnątrz pętli - listenery nie będą potrzebne. Cała symulacja powinna być synchroniczna i uzależniona od czasu.

Tutaj masz przykład takiej pętli:

long last_time = System.nanoTime();

while(running) {
    long time = System.nanoTime();
    int delta_time = (int) ((time - last_time) / 1000000);
    last_time = time;
}

Hasła do google: game loop, delta time

0
Berylo napisał(a):

Powinieneś to zrobić trochę inaczej. Dodawanie gazu jest zależne od prędkości procesora. Na wolnym komputerze dodawać się będzie wolniej niż na szybkim. Musisz to uzależnić od czasu.
Zrób sobie pętle, w której będziesz sprawdzał ile upłynęło czasu pomiędzy wykonaniami. Jeśli sobie ustalisz np 60fps to oznacza, że pomiędzy klatkami musiało upłynąć 16ms. Jeśli upłynęło to robisz operację (np gaz, jeśli nie to nic nie robisz i puszczasz pętle jeszcze raz). To taki uproszczony mechanizm. Dzięki temu będziesz mógł zaimplementować sobie spadek obrotów jeśli gaz nie jest wciśnięty, a nawet dostosować prędkość spadania obrotów.

Jeśli chodzi o obsługę przycisków to musisz to robić synchronicznie. To znaczy, sprawdzasz programistycznie isPressed na JButton wewnątrz pętli - listenery nie będą potrzebne. Cała symulacja powinna być synchroniczna i uzależniona od czasu.

Tutaj masz przykład takiej pętli:

long last_time = System.nanoTime();

while(running) {
    long time = System.nanoTime();
    int delta_time = (int) ((time - last_time) / 1000000);
    last_time = time;
}

Hasła do google: game loop, delta time

Rozumiem, że jest wiele rzeczy, które powinienem zrobić inaczej, lecz już chciałbym to na razie zostawić jak jest i ewentualnie później to zmienić, tymczasem chciałbym tylko zapętlić coś w stylu:

while (true) {
      if (!gaz.isPressed) {
            obroty--;
            ....
            sleep(200);
}

dałoby rade jakoś to zrobić? :P

1

Da radę ale musisz to puścić w osobnym wątku

0
Berylo napisał(a):

Da radę ale musisz to puścić w osobnym wątku

Właśnie o tym słyszałem, ale nie wiem jak taki wątek zrobić, naprowadziłbyś jakoś?

1
Berylo napisał(a):

http://tutorials.jenkov.com/java-concurrency/creating-and-starting-threads.html

Dziękuje za pomoc, wszystko działa jak należy, teraz tylko ulepszać :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1