C, PHP, VB, .NET

Дневникът на Филип Петров


* Игра с падащи букви с Netbeans

Публикувано на 19 април 2018 в раздел УКИ.

Ще направим класическа игра, в която падат по вертикала букви, а вие трябва да ги нацелвате същите на клавиатурата. Отворете нов проект с NetBeans. Създайте следния дизайн:

Забележете, че работим с Layout „null“. Това е силно непрепоръчително за нормални desktop приложения. Нашият прозорец обаче няма да се разтегля – той ще е с фиксирани размери и няма да може да се разтегля (направете го). За удобство, препоръчвам първо да наместите обектите с „free design“ и след това да смените layout на null – много по-лесно ще е.

Причината да използваме null layout e, че при всяка уцелена буква, ние не само ще я преместваме обратно най-горе, но и ще ѝ променяме текста. Това ще променя размерите на обекта, което автоматично при друг Layout ще предизвиква неприятен reset (може да опитате по-късно, когато програмата е реализирана, и ще видите за какво говоря).

Обектите jLabel1, …, jLabel6 са буквите най-горе. Обектът score е числото долу вдясно. За всички тези обекти настройте характеристиките им preferredSize, minimumSize и maximumSize да са точни размери (постарайте са да са достатъчно широки така, че да хващат най-широката буква, например пробвайте с „W“). При null layout оразмеряването на обектите се прави задължително ръчно.

Сега отидете в кода. Добавете две член променливи – списък, в който за удобство ще запишем вече създадените JLabel обекти и булева променлива, която ще служи за индикация „край на играта“:

LinkedList<JLabel> theLetters = new LinkedList<>();
boolean gameOver = false;

Променете конструктура на основния JFrame и направете така, че буквите за излезнат извън екрана (това може да се направи и от характеристиките на самите бутончета така, че да се случи директно при тяхното създаване, но така ще бъде по-трудно манипулирането им чрез дизайнера впоследствие), както и ги добавете в списъка:

public FallingLetters() {
 initComponents();
 jLabel1.setLocation(jLabel1.getX(),-20);
 jLabel2.setLocation(jLabel2.getX(),-120);
 jLabel3.setLocation(jLabel3.getX(),-80);
 jLabel4.setLocation(jLabel4.getX(),-160);
 jLabel5.setLocation(jLabel5.getX(),-200);
 jLabel6.setLocation(jLabel6.getX(),-40);
 theLetters.add(jLabel1);
 theLetters.add(jLabel2);
 theLetters.add(jLabel3);
 theLetters.add(jLabel4);
 theLetters.add(jLabel5);
 theLetters.add(jLabel6);
}

Сега ще създадем таймер (директно като член променлива), с който всяка една буква ще я пускаме да пада надолу с един пиксел през интервал от 10 милисекунди:

Timer t = new Timer(10, new ActionListener() {
   @Override
   public void actionPerformed(ActionEvent ae) {
      for(JLabel letter: theLetters){
         letter.setLocation(letter.getX(),letter.getY()+1);
         if(letter.getY()+letter.getHeight()>SwingUtilities.getRootPane(letter).getHeight()){
            gameOver = true;
            ((Timer)ae.getSource()).stop();
         }
      }
   }
});

Забележете командата вътре в if, с която таймера спира сам себе си – това е нетривиална за изпълнение задача. Също така, понеже си спестихме създаването на отделен панел, към който да имаме директна референция, трябва да се обръщаме към екрана на основния фрейм чрез SwingUtilities.getRootPane(…). Направих го нарочно, за да демонстрирам тази техника. В учебна ситуация е по-добре или да работите с панел, към който имате референция, или (при нужда от максимално улеснение в задачата) да използвате „магически числа“ за дължината на екрана.

Остана последно да добавите KeyPress събитие, с което да следим за натискане на бутон от клавиатурата. Ако този бутон е същия символ както някоя от падащите букви, то я преместваме обратно в позиция 0 по вертикала и ѝ сменяме буквата с нова, която е произволна:

private void formKeyTyped(java.awt.event.KeyEvent evt) { 
   if(gameOver){
      return;
   }
   for(JLabel letter: theLetters){
      if(letter.getText().equalsIgnoreCase(""+evt.getKeyChar())){
         letter.setLocation(letter.getX(),0);
         int currentScore = Integer.parseInt(score.getText());
         currentScore++;
         score.setText(""+currentScore);
         Random r = new Random();
         char c = (char)(r.nextInt(26) + 'A');
         letter.setText(""+c);
      }
   }
}

Остава да стартирате таймера при WindowOpened събитие на JFrame формата и с това програмата ще бъде готова. Ето как би изглеждал екрана при една примерна реална игра:

Ако желаете, може да изтеглите и готов сорс код.

Допълнителна задача 1. Направете така, че буквите да са произволни от самото начало.

Допълнителна задача 2. Направете така, че да може да падат и малки букви (т.е. направете играта case-sensitive).

Допълнителна задача 3. Направете така, че първоначално буквите да падат по-бавно, но с всяка уцелена буква постепенно падането на всички останали да се забързва.

Допълнителна задача 4. Помислете как може да реализирате вместо падащи букви, една голяма падаща дума (да речем избрана произволно от малък речник, който ще създадете сами).

 



Добави коментар

Адресът на електронната поща няма да се публикува


*