Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Апплеты > Змейка


Автор: invis87 4.4.2009, 12:40
Всем привет.
Не так давно начал изучать яву, и из-за необходимости практики решил написать своё приложение, так как нормальных идей нету остановился на змейке.
Итак змейку я представил как ArrayList содержащий в себе экземпляры класса отдельных кусочков её хвоста (квадратиков).
Шаг представляется добавлением нового экземпляра квадратика и стиранием предыдущего, но вот как раз в этом месте у меня косяк :(

Простой класс, нет ничего особенного и описывать не буду smile
Код

/**
 * Направления.
 */
public class Direction {
    protected static final byte UP=0, DOWN=1, LEFT=3, RIGHT=2;
    /**
     * текущее направление
     */
    private byte NOW;
    /**
     * Конструктор, первоначально змея смотрит вверх.
     */
    public Direction(){
        NOW=UP;
    }
    /**
     * Поворачивает змею.
     * @param WHERE куда повернуть
     */
    public void turn(byte WHERE){
        if((NOW==UP && WHERE!=DOWN) ||
           (NOW==LEFT && WHERE!=RIGHT) ||
           (NOW==DOWN && WHERE!=UP) ||
           (NOW==RIGHT && WHERE!=LEFT))
             NOW=WHERE;
    }
    
    public byte getNOW(){
        return NOW;
    }
}


Класс апплета, вроде тоже ничего сложного, надо сказать что пробел имитирует съедание змейкой одного объекта и фон чёрный для того чтобы было понятно как происходит движение змеи:
Код

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
 
public class Game extends JApplet implements Runnable{
    private Direction direction = new Direction();
    Snake our_snake = new Snake();
    
    public Game(){
        setBackground(Color.BLACK);
        addKeyListener(new KeyAdapter(){
            @Override
            public void keyPressed(KeyEvent e) {
               switch(e.getKeyCode()){
                   case KeyEvent.VK_DOWN:
                       direction.turn(Direction.DOWN);break;
                   case KeyEvent.VK_UP:
                       direction.turn(Direction.UP);break;
                   case KeyEvent.VK_LEFT:
                       direction.turn(Direction.LEFT);break;
                   case KeyEvent.VK_RIGHT:
                       direction.turn(Direction.RIGHT);break;
                   case KeyEvent.VK_SPACE:
                       our_snake.add();
               }
            }
        });        
    }

    @Override
    public void paint(Graphics g){
        // g.clearRect(0, 0, getWidth(), getHeight());
        showStatus(Integer.toString(our_snake.ckolko()));
        our_snake.step(direction);
        our_snake.paint(g);
    }

    public void run() {
        for(;;){
            try {
            Thread.sleep(250);
            } catch (InterruptedException ex) {}
        repaint();
      }
    }

    @Override
    public void start() {
    Thread thread = new Thread(this);
    thread.setPriority(Thread.MIN_PRIORITY);
    thread.start();
    }
  }


И основной класс, который описывает змею, по идее тоже всё просто, но у меня косяк в методе paint, я не понимаю почему если добавить один квадратик, то предыдущие перестанут закрашиваться белым :( в этом основной косяк.
Код

import java.awt.*;
import java.util.ArrayList;

public class Snake {
    /**
     * Класс описывает поведение каждого отдельного квадрата
     * хвоста змеи.
     */
    private class Square{
        int NOW_X , NOW_Y;
 
        private Square(){}

        private void paint(int x, int y, int part, Graphics g){
            g.setColor(Color.green); // хвост зелёный
            g.fillRect(x, y, part, part); //квадратный
            NOW_X = x;
            NOW_Y = y;
        }

        private void erase(int part, Graphics g){
            g.setColor(Color.white);
            g.fillRect(NOW_X, NOW_Y, part, part);
        }

        private int getNOW_X(){
            return NOW_X;
        }

        private int getNOW_Y(){
            return NOW_Y;
        }
    }
    /**
     * Динамический массив содержит все отдельные части хвоста змеи.
     */
    ArrayList<Square> al = new ArrayList(4);
    /**
     * Ширина и высота одной части змеи
     */
    private final int part = 6;
    /**
     * Текущие координаты.
     */
    private int x=200,y=225;
    /**
     * С помощью этого флага удлиняем змейку.
     */
    private boolean delete = true;
    /**
     * Конструктор
     */
    Snake(){ al.add(new Square());}

    protected void paint(Graphics g){
        if(delete){
            al.get(al.size()-1).erase(part, g);  // мне кажется элементы не стираются когда их больше одного из-за отсутствия имени у экземпляра
                                                                 // класса, хотя может я не прав, это просто догадака
            al.remove(al.size()-1);        
        }
        delete = true;
        al.add(new Square());           // попробуйте перенести эти строки в начало метода
        al.get(0).paint(x, y, part, g); // опять же почему будет такой результат я не понимаю, стираться всё-равно же должно 
    }

    protected void add(){
        delete = false;
    }

    public int ckolko(){
        return al.size();
    }

    protected void step(Direction direction){
        switch(direction.getNOW()){
        case Direction.UP:
            y -= 6;break;
        case Direction.DOWN:
            y += 6;break;
        case Direction.LEFT:
            x -= 6;break;
        case Direction.RIGHT:
            x += 6;break;
        }
    }
}


Автор: Kangaroo 5.4.2009, 00:53
Элементы добавляются в конец списка; попробуй так:
Код

if(delete){
            al.get(0).erase(part, g);  // тут использовать 0
            al.remove(0);        
        }
        delete = true;
        al.add(new Square());           
        al.get(al.size()-1).paint(x, y, part, g); // а тут - последний элемент

Автор: invis87 5.4.2009, 16:19
БЛИИИИИИИИИИИН !!!
Спасибо огромное, на такой фигне тупанул, заработало всё !!! Ура smile

Автор: invis87 13.4.2009, 23:59
Довёл до разума. Всё ещё сырая, но играть можно smile
Буду рад услышать критику.
http://webfile.ru/3410028

Snake.java
Код
import java.awt.*;
import java.util.Random;
import java.util.ArrayList;
/**
 *
 * @author invis
 */
public class Snake {
    /**
     * Класс описывает поведение каждого отдельного квадрата
     * хвоста змеи.
     */
    private class Square{
        private int NOW_X , NOW_Y;
 
        private Square(){}

        private void paint(int x, int y, int part, Graphics g){
            g.setColor(Color.green); // хвост зелёный
            g.fillRect(x, y, part, part); //квадратный
            NOW_X = x;
            NOW_Y = y;
        }

        private void erase(int part, Graphics g){
            g.setColor(Color.white);
            g.fillRect(NOW_X, NOW_Y, part, part);
        }
    }
    /**
     * Динамический массив содержит все отдельные части хвоста змеи.
     */
    ArrayList<Square> al = new ArrayList(4);
    /**
     * Ширина и высота одной части змеи
     */
    private final int part = 6;
    /**
     * Объект для рисования "еды" в случайном месте.
     */
    Random random = new Random();
    /**
     * Текущие координаты.
     */
    private int x=216,y=216;
    /**
     * Координата Х "еды".
     */
    private int eatX;
    /**
     * Координата Y "еды".
     */
    private int eatY;
    /**
     * С помощью этого флага удлиняем змейку.
     */
    private boolean delete = true;
    /**
     * Создана ли уже "еда" для змейки.
     */
    private boolean alreadyCreate = false;
    /**
     * Жива ли змея.
     */
    protected boolean alive = true;
    /**
     * Конструктор создаёт один экземпляр квадратика.
     */
    Snake(){ al.add(new Square());}

    protected void paint(Graphics g){
        if(delete){
            al.get(0).erase(part, g);
            al.remove(0);
        }else{delete = true;}
        al.add(new Square());
        al.get(al.size()-1).paint(x, y, part, g);
    }

    public int gdeY(){
        return al.get(al.size()-1).NOW_Y;
    }

    public int gdeX(){
        return al.get(al.size()-1).NOW_X;
    }

    protected void step(Direction direction){
        switch(direction.getNOW()){
        case Direction.UP:
            y -= 6;break;
        case Direction.DOWN:
            y += 6;break;
        case Direction.LEFT:
            x -= 6;break;
        case Direction.RIGHT:
            x += 6;break;
        }
        //не врезалась ли змейка в стену
        if(x > 471 || x < 4 || y > 471|| y < 4){
            alive=false;
        }
        //не съела ли змейка себя
        for (int i = 0; i < al.size()-1; i++) {
           if (x == al.get(i).NOW_X &&
               y == al.get(i).NOW_Y){
               alive=false;
               }
        }
    }
    /**
     * Рисует "еду" для змейки в случайном месте.
     * @param g
     */
    protected void food(Graphics g){
        if(eatX == x && eatY == y){
            alreadyCreate = false;
        }
        if(!alreadyCreate){
            eatX = (random.nextInt(77)+1)*6;
            eatY = (random.nextInt(77)+1)*6;
            g.setColor(Color.BLUE);
            g.fillRect(eatX, eatY, part, part);
            //добавить квадратик к змее.
            delete = false;
            alreadyCreate = true;
        }
    }
}


Direction.java
Код
/**
 * Направления.
 * @author invis
 */
public class Direction {
    protected static final byte UP=0, DOWN=1, LEFT=3, RIGHT=2;
    /**
     * текущее направление
     */
    private byte NOW;
    /**
     * Конструктор, первоначально змея смотрит вверх.
     */
    public Direction(){
        NOW=UP;
    }
    /**
     * Поворачивает змею.
     * @param WHERE куда повернуть
     */
    public void turn(byte WHERE){
        if((NOW==UP && WHERE!=DOWN) ||
           (NOW==LEFT && WHERE!=RIGHT) ||
           (NOW==DOWN && WHERE!=UP) ||
           (NOW==RIGHT && WHERE!=LEFT))
             NOW=WHERE;
    }
    
    public byte getNOW(){
        return NOW;
    }
}


Game.java
Код

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
/**
 *
 * @author invis
 */
public class Game extends JApplet implements Runnable{
    private Direction direction = new Direction();
    Snake our_snake = new Snake();
    /**
     * Флаг нужнг для передачи фокуса во время первого рисования.
     */
    boolean mFirstPaint = true;
    
    public Game(){
        setSize(480, 480);
        setBackground(Color.white);
        addKeyListener(new KeyAdapter(){
            @Override
            public void keyPressed(KeyEvent e) {
               switch(e.getKeyCode()){
                   case KeyEvent.VK_DOWN:
                       direction.turn(Direction.DOWN);break;
                   case KeyEvent.VK_UP:
                       direction.turn(Direction.UP);break;
                   case KeyEvent.VK_LEFT:
                       direction.turn(Direction.LEFT);break;
                   case KeyEvent.VK_RIGHT:
                       direction.turn(Direction.RIGHT);break;
               }
            }
        });        
    }
    /**
     * Выводит сообщение о поражении.
     */
    public void loose(){
        getGraphics().drawString("LOOSER", 220, 230);
    }

    @Override
    public void paint(Graphics g){
        // передаём фокус апплету
        if (mFirstPaint){
            mFirstPaint = false;
            requestFocus();
        }
        showStatus("X - " + Integer.toString(our_snake.gdeX()) + "; Y - " + Integer.toString(our_snake.gdeY()));
        g.setColor(Color.black);
        g.drawRect(4, 4, 471, 471);
        our_snake.step(direction);
        our_snake.paint(g);
        our_snake.food(g);
    }

    public void run() {
        while(our_snake.alive){
            try {
            Thread.sleep(100);
            } catch (InterruptedException ex) {}
            repaint();
        }
        if(!our_snake.alive){loose();return;}
    }

    @Override
    public void start() {
    Thread thread = new Thread(this);
    thread.setPriority(Thread.MIN_PRIORITY);
    thread.start();
    }
  }

P.S. лучше открывать в appletviewer. У меня googlechrome и если апплет открыть 5-й страницей, то он немного подлагивает.
P.S.S Такая большая скорость только из-за того, что поле большое.

Автор: zoidberg 12.5.2009, 09:23
Змейка клевая, убил на нее минут 20. Классика - затягивает. %)

Автор: KapsuL 14.6.2009, 23:28
чёт не могу сделать проект....ето ведь в NetBeans пишется???ява апликейшн или десктоп ява апликешн...?после того как создаю проект и классы пишет что не найден мейн класс... smile

Добавлено через 6 минут и 32 секунды
после запуска выдаёт такое:
а ещё плюётся на import java.awt.*;

Автор: korob2001 21.6.2009, 11:16
Цитата(KapsuL @  14.6.2009,  20:28 Найти цитируемый пост)
чёт не могу сделать проект....ето ведь в NetBeans пишется???ява апликейшн или десктоп ява апликешн...?после того как создаю проект и классы пишет что не найден мейн класс...

Вообще-то это апплет.
1. Положи все файлы .java в один каталог.
2. В терминале дай команду javac /путь к каталогу/Game.java
3. В тот же каталог положи такой HTML файл:
Код

<html>
    <head>
        <title>Snake</title>
    </head>
    <body>
        <applet code="Game" width="500" height="600"></applet>
    </body>
</html>

4. Открой этот html в браузере.

Автор: KapsuL 22.6.2009, 12:16
спасибо, разобрался)) smile 

Автор: invis87 27.6.2009, 18:24
Я нашёл баг smile
 Синий квадратик может появиться прямо на змейке smile в этом случае когда последний квадрат змеи по нему проедет то он исчезнет, но съесть всё-равно можно ^^

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)