* Елемент от игра с NetBeans
Публикувано на 19 ноември 2015 в раздел УКИ.
В тази статия ще покажем съвсем елементарен фрагмент от игра наподобяваща популярната змия. След като вече сте решили всичко от предишната задача, ще добавим още един графичен обект на екрана - малък триъгълник. Ще направим така, че нашата топка да "яде" триъгълника, с което ще се увеличава краен резултат с една точка.
Реализирайте работния екран в нещо подобно на това:
Именовайте JLabel обекта на триъгълника като "theTriangle", а текстовото полето на резултата като "result".
Сега нашето кръгче ще се движи по екрана. Идеята е да направим така, че ако влезе вътре в триъгълника, да увеличаваме резултата с 1, а триъгълника да се премести на произволно място на екрана. Добавете следния метод някъде в тялото на основния клас:
private void checkIfCircleIsInTriangle(){ if(theBall.getLocation().x >= theTriangle.getLocation().x && theBall.getLocation().y >= theTriangle.getLocation().y && (theBall.getLocation().x + theBall.getWidth()) <= (theTriangle.getLocation().x + theTriangle.getWidth()) && (theBall.getLocation().y + theBall.getHeight()) <= (theTriangle.getLocation().y + theTriangle.getHeight()) ){ result.setText(""+(Integer.parseInt(result.getText())+1)); theTriangle.setLocation((int)(ballPanel.getWidth()*Math.random()), (int)(ballPanel.getHeight()*Math.random())); } }
Проверките в if условието са за това дали топката е изцяло вътре в полето на триъгълника. Ако оставим настрани факта, че на екрана виждаме кръгче и триъгълник, реално картинките са правоъгълници. Това е и причината да не им направя фона прозрачен, а да се вижда бялата рамка - по този начин това се вижда ясно. В тялото на if условието преместваме триъгълника на ново място на екрана. Math.random() е метод, който връща число от 0 до 1.
Сега този добавен от нас нов метод трябва да го извикаме на няколко места. Първото е там, където местим кръгчето с клавиатурата. Добавете следния ред в края на метод formKeyPressed (събитието за натиснат бутон):
checkIfCircleIsInTriangle();
Добавете същия ред и в actionPerformed методите за всеки един от четирите метода за натиснати бутони moveLeft, moveRight, moveUp и moveDown. Готово! Вече вашата топка ще "яде" триъгълниците. От тук нататък можете да фантазирате и доработвате програмата - например да се добавят таймери за състезание кой най-бързо ще достигне резултат 10 и подобни. Чрез многонишково програмиране можем да направим така, че триъгълника да "бяга" от нас. Подобни техники ще покажем по-нататък.
При подобни задачи учениците обикновено задават следния логичен въпрос - не може ли да движим топчето и по диагонал? До този момент то се движи само в една от четирите посоки. Добавянето на бутони за движение по диагонал не е трудно. Направете го. Много по-сложен е момента с "два едновремено натиснати бутона от клавиатурата". Реално ние имаме едно единствено събитие - натиснат бутон. Нямаме второ, което да е "натиснат още един бутон".
Правилният начин да се справим с този проблем е да престанем със сегашната тъй или иначе неправилна тактика и да използваме два Timer обекта, които практически ще местят обектите в отделни нишки. За повече информация вижте края на статията (послеписа) тук: https://www.cphpvb.net/uki/9866-ballmover-netbeans/
Другият начин, който нарочно ще изложим, е да се прави така, че "да помним" кой бутон в момента е натиснат. Това е и подходящ момент за запознаване на учениците с първия тип структура от данни - множеството. Ако премълчим техническите характеристики на множеството (вижте статиите за речници и множества в раздел Java), с тях се работи много лесно.
В началото на класа BallMover добавете следния ред:
private final static Set<Integer> KEYSPRESSED = new HashSet<>();
С това създадохме константа (final) от тип множество с име KEYSPRESSED. Когато натиснем бутон, ще искаме да добавяме кода на бутона (той е число) в това множество. Това става по следния начин - отидете в метода за събитието при натиснат бутон (formKeyPressed) и добавете следния ред в неговото начало:
KEYSPRESSED.add(evt.getKeyCode());
Метод add на множеството (Set) добавя елемент в множеството.
Сега ще проверим дали в множеството има точно определени комбинации от елементи - (наляво, надолу), (наляво, нагоре), (надясно, надолу) и (надясно, нагоре). Други "блокиращи се" комбинации като (наляво, надясно) и (нагоре, надолу), както и повече от два натиснати бутона не ни интересуват. Ако няма такава комбинация, ще извършваме досегашното действие - местене в посока на текущо натиснатия клавиш. Целият метод formKeyPressed ще бъде променен по следния начин:
private void formKeyPressed(java.awt.event.KeyEvent evt) { KEYSPRESSED.add(evt.getKeyCode()); int currentBallX = theBall.getLocation().x; int currentBallY = theBall.getLocation().y; if(KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_LEFT) && KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_DOWN) ){ theBall.setLocation(currentBallX-1, currentBallY+1); } else if(KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_LEFT) && KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_UP) ){ theBall.setLocation(currentBallX-1, currentBallY-1); } else if(KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_RIGHT) && KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_DOWN) ){ theBall.setLocation(currentBallX+1, currentBallY+1); } else if(KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_RIGHT) && KEYSPRESSED.contains(java.awt.event.KeyEvent.VK_UP) ){ theBall.setLocation(currentBallX+1, currentBallY-1); } else{ switch(evt.getKeyCode()){ case java.awt.event.KeyEvent.VK_LEFT: theBall.setLocation(currentBallX-1, currentBallY); break; case java.awt.event.KeyEvent.VK_RIGHT: theBall.setLocation(currentBallX+1, currentBallY); break; case java.awt.event.KeyEvent.VK_UP: theBall.setLocation(currentBallX, currentBallY-1); break; case java.awt.event.KeyEvent.VK_DOWN: theBall.setLocation(currentBallX, currentBallY+1); break; } } checkIfCircleIsInTriangle(); }
Остава да направим последно важно нещо - ако освободим даден клавиш, трябва да го премахнем от множеството. На основната рамка добавете Event от тип KeyReleased. В него добавете следния код:
private void formKeyReleased(java.awt.event.KeyEvent evt) { KEYSPRESSED.remove(evt.getKeyCode()); }
Метод remove на множество премахва елемент от него.
Допълнителна задача 1: Добавете четирите бутона за движение по диагонал със стъпка 10
Допълнителна задача 2: Ще забележите, че триъгълничето понякога излиза от екрана. Направете така, че това да не може да се получава. Същото направете и за топчето.
Допълнителна задача 3: При показаното решение ще забележите неприятен ефект - при движение по диагонал и пускане на един клавишите, в някои случаи топчето ще продължава да се движи, а в други случаи ще спира. Например ако първо сте натиснали наляво, а после нагоре (движите се в североизточна посока) и пуснете клавиш нагоре, топчето ще спре. Ако първо сте натиснали първо нагоре, а после наляво (същото движение на североизток), след което пуснете клавиш нагоре, топчето ще продължи наляво (няма да спре). Обсъдете на какво може да се дължи този проблем и предложете решение.
Допълнителна задача 4: Направете така, че да се трупа точка не когато топчето влезе изцяло вътре в полето на триъгълника, а когато само го докосне.
Допълнителна задача 5: Преправете всичко така, че да работите правилно с Таймери. Ще забележите, че кодът в крайна сметка ще се опрости, защото няма да има нужда от HashSet и помнене на това кой клавиш е натиснат - просто ще спирате и пускате два различни таймера за нагоре и надолу.
Добави коментар