motofan logo
3 страниц V < 1 2 3 >        
> 

Игровая комната, Обмен опытом при создании игр

Stranger
сообщение 12.10.2006, 20:10 Закрепленное сообщение!


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



Итак, Вы хотите делать игры... Вам мало бесконечных поисков всевозможных модификаций Вашего телефона, мало непрерывных прошиваний, тюнингов, патчинга, твикинга...Вам нужно что-то еще, у Вас есть голый энтузиазм плюс жгучее желание делать что-то свое, выражая себя, тем самым выделяя свое существование из серой и однообразной повседневности...
Вы что-то слышали про Java, видели даже надпись J2ME на коробке из-под своего мобильного. В глубине души Вы всегда оставались ребенком, Вы играли, а жизнь играла Вами...У Вас всегда под рукой были самые любимые игрушки, теперь же Вы хотите сами их делать...ну что ж...я постараюсь Вам помочь

Что есть мобильные игры? Как они возникли? Какими были сначала?
В 1997 году на телефонах Нокия была впервые предустановлена мобильная игра. Это была всемирно известная "Змейка" (Snake). Несмотря на кажующуюся простоту, невзрачность графики и примитивность игровой логики, эта игра стала предвестником изменения образа мобильного телефона - перерождения его из средства общения в средство развлечения. С тех пор прошло уже немало лет. Утекло немало воды. Новые веяния, мысли и идеи управляют рынком мобильных развлечений. "Ландшафт" мобильных игр быстро меняется. И хотя этот рынок еще жестко не сегментирован, уже четко можно выделить лидеров, на которых равняются все остальные производители(думаю посетители Мотофана знают о ком я говорю :)...)
Правда есть одно "но"... Говорят, что деньги правят миром. Говорят, что сильнее те, у кого их больше. Думаю, вряд ли...Талант, вдохновение, настойчивость и упорство, четкое видение цели и отсутствие боязни сопутствующих по жизни трудностей - вот, что поможет преодолеть все на Вашем пути...Так что дерзайте...Возможно за нами будет будующее новых технологий и новых развлечений...

Что такое Java?
Java зарождался как проект в Sun, цель которого заключалась во внедрении компьютеров в повседневную жизнь...Пришло время, когда технологии и потребности на рынке совпали с исходным назначением языка. Тогда Sun подняла свои наработки и приспособила Java для мобильных телефонов. J2ME стал подмножеством более глобального инструмента Java, который состоит из языка программирования, API и среды выполнения.
Я не буду Вас учить как программировать на J2ME и тем более на Java . Не потому, что не хочу. Нет. Нельзя научить тому, что для самого является источником ежедневных открытий и удивлений. Не верьте тому, кто говорит, что знает все. Все и ничто - суть одно. Без пустого не было бы полного. И наоборот. Поэтому я просто расскажу, что и как делаю я. А решать уж Вам. Согласны ?
Итак, вернусь к тому, с чего начал :) Вы хотите делать мобильные игры... У меня к Вам вопрос: у Вас есть идеи, какую игру написать? Если так, то Вы счастливый человек, ведь идея - это самая важная часть процесса создания игры. Моя карьера J2ME-программиста началась именно так : с яркой и необычной идеи...
Если Вам тяжело, не унывайте. Я Вам помогу. Мы напишем простенький арканоид. Да, да, эта такая простенькая симпатичная игра, где битка отбивает летающий мячик, при этом стараясь разбить им различные кирпичики, набирая очки и жизни. Простенькая в том смысле, что в ней не будет много уровней, бонусов и прочих украшательств. Все это Вы сделаете сами, если захотите. Я же дам основу. Итак, начнем-с...

Цитата
"Основной элемент программы, написанной на языке Java, - это класс(class)."
Точнее и не скажешь. Из всего множества доступных нам знаний и представлений, лежащих в основе постановки задачи нам необходимо выбрать такие непересекающиеся его подмножества, которые бы мы могли классифицировать, как отдельные объекты. Что мы имеем? Есть битка. Она одна и кроме ее координат, размеров и направления перемещения нам от нее ничего и не нужно...Ради одного элемента создавать отдельный класс...правильно не будем... :) Кирпичики(бриксы). Так-так. Подождите. Сколько их будет? Один, два, три...а может четыре. Не путайте людей людей. Их будет много. Сколько захотите. И все они будут разные. Создадим отдельный класс Brick. Думаю, что полями данного класса могут являться следующие элементы:

Код

  private int xPos; // х-я координата отдельного кирпичика
  private int yPos; //у - я координата отдельного кирпичика
  private int typeBrick; // тип кирпичика(содержит бонус или нет)
  private int brickColor; //цвет
  private boolean isCracked; // разбит или нет
  private Bonus bonus = null; // содержащийся внутри бонус

Как Вы видите, среди полей данного класса есть поле Bonus bonus. Еще один класс? Да, и о нем я расскажу немного позже.
Добавим к описанным полям еще немного:

Код
  public static final int RED = 0xff0000; //константа, задающая красный цвет кирпичика
  public static final int GREEN = 0x00ff00; // зеленый
  public static final int BLUE = 0x0000ff; // синий

  public static final int NORMAL = 0; //константа, обозначающая, что кирпичик без бонусов
  public static final int BONUS = 1; // "бонусный" кирпич

  public static final int POINTS_RED = 5; //очки, за красный кирпич
  public static final int POINTS_GREEN = 7; // за зеленый
  public static final int POINTS_BLUE = 10; // за синий

  private Random rand = new Random(); //генератор случайных чисел

Думаю, здесь все понятно. Просто статические константы, обозначающие цвет, тип кирпичика, а также кол-во очков, получаемое за его разбитие. Также имеется генератор случайных чисел Random rand, который мы будем использовать для распределения бонусов между кирпичами. Погодите, а как же конструктор скажете Вы? Секундочку...Вот он:
Код

public Brick(int xPos, int yPos, int typeBrick, int brickColor) {
     this.xPos = xPos;
     this.yPos = yPos;
     this.typeBrick = typeBrick;
     this.brickColor = brickColor;
     if (typeBrick == BONUS) {
       int typeBonus =  Math.abs(rand.nextInt() % 7);
       bonus = new Bonus(xPos, yPos, typeBonus);
     }
  }

Инициализируем нужные поля + если кирпич должен содержать бонус, даем его случайным образом(при этом держим в уме, что я Вам должен рассказать про класс бонусов :))
Также в классе Brick имеются "геттеры и сеттеры". Тут, я думаю, тоже не должно возникнуть проблем:
Код

//Возвращаем х-вую координату кирпича
 public int getPosX(){
     return xPos;
  }
//Возвращаем у-вую координату кирпича
  public int getPosY() {
     return yPos;
  }
//Возвращаем тип кирпича
  public int getTypeBrick(){
     return typeBrick;
  }
//Возвращаем цвет кирпича
  public int getColorBrick(){
     return brickColor;
  }

//Устанавливаем х-вую координату кирпича
public void setPosX(int xPos) {
     this.xPos = xPos;
  }
//Устанавливаем у-вую координату кирпича
  public void setPosY(int yPos) {
     this.yPos = yPos;
  }
//Проверяем разбит ли кирпич
  public boolean isCrackedBrick() {
     return isCracked;
  }
//Разбиваем кирпич
  public void setCrackedBrick(){
     isCracked = true;
  }
//Берем ссылку на бонус у данного кирпича
  public Bonus getBonus() {
     return bonus;
  }

Ну и напоследок метод отрисовки нашего отдельного кирпичика:

Код

public void drawBrick(Graphics g) {
     g.setColor(brickColor);
     g.fillRoundRect(xPos + (Data.SCREEN_WIDTH - Data.FIELD_WIDTH) / 2, yPos , Data.BRICK_WIDTH, Data.BRICK_HEIGHT, 5, 5);
  }

Перейдем наконец к описанию класса Bonus. Как я уже сказал, каждый кирпичик может потенциально содержать бонус. Первая порция полей для данного класса практически идентична полям класса Brick:
Код

  private int xPos;
  private int yPos;
  private int typeBonus;
  private boolean isFlying = false;

Исключением лишь является поле isFlying , отвечающее за то, летит ли бонус или нет.
Есть свои константы и у этого класса(названия говорят сами за себя :)):
Код

  public static final int BONUS_DOUBLE_LENGTH_RACKET = 0;
  public static final int BONUS_HALF_LENGTH_RACKET = 1;
  public static final int BONUS_NORMAL_LENGTH_RACKET = 2;
  public static final int BONUS_DOUBLE_SPEED_BALL = 3;
  public static final int BONUS_HALF_SPEED_BALL = 4;
  public static final int BONUS_NORMAL_SPEED_BALL = 5;
  public static final int BONUS_END_LEVEL_BRICK = 6;

Конструктор + "геттеры и сеттеры" приводить не буду, они практически аналогичны таковым из предыдущего класса. Интерес представляют два метода:

Код
public void drawBonus(Graphics g) {
     int color = 0xffffff;
     String bonusName = "";
     switch (typeBonus) {
        case BONUS_DOUBLE_LENGTH_RACKET:  bonusName = "L"; color = 0xffffff;break;
        case BONUS_HALF_LENGTH_RACKET: bonusName = "H"; color = 0xff00ff;break;
        case BONUS_DOUBLE_SPEED_BALL: bonusName = "F"; color = 0xffff00;break;
        case BONUS_HALF_SPEED_BALL: bonusName = "S"; color = 0x1ffff2;break;
        case BONUS_END_LEVEL_BRICK: bonusName = "E"; color = 0x00ff00;break;
        case BONUS_NORMAL_LENGTH_RACKET: bonusName = "N"; color = 0x20ff10;break;
        case BONUS_NORMAL_SPEED_BALL: bonusName = "N"; color = 0xa0ff22;break;
     }
     g.setColor(color);
     g.drawString(bonusName, xPos + (Data.SCREEN_WIDTH - Data.FIELD_WIDTH) / 2, yPos, g.TOP | g.HCENTER);
  }

Данный метод отвечает за отрисовку бонуса на дисплее телефона. Как Вы видите, изображение бонуса представляет собой буковку, которую Вам нужно будет либо поймать либо пропустить. И всего то. Думаю, понятно, что внеся незначительные изменения в данный класс, можно качественно повысить "красоту" отображения бонусов.
Второй метод:

Код
public void handle() {

     if (++yPos > (Data.FIELD_TOP + Data.FIELD_HEIGHT)) {
        isFlying = false;
     }
  }

Это своеобразный "моторчик" бонуса, заставляющий его "падать" вниз до конца поля.
Если же бонус пролетел, и Вы не успели его поймать, то бонус меняет значение своего поля isFlying на false и исчезает из виду.
При описании этих двух классов Вы не могли не заметить, что в коде встречаются упоминания некого класса Data, из которого мы получаем значения различных статический полей, например, в последнем методе : Data.FIELD_HEIGHT. Что это за класс.
Для меня он был своеобразным хранилищем констант и не более. Вот он:

Код
public class Data {

  public final static int SCREEN_WIDTH = 176; //Размер экрана телефона по ширине(в пикселях)
  public final static int SCREEN_HEIGHT = 204; // Размер экрана телефона по высоте(в пикселях)

  public final static int FIELD_WIDTH = 100; // Ширина игрового поля( в пикселях)
  public final static int FIELD_HEIGHT = 125; // Высота

  public final static int FIELD_TOP = 20; // Смещение верхнего края игрового поля от начала экрана по вертикали(в пикселях)

  public final static int RACKET_WIDTH = 20; //Ширина битки
  public final static int RACKET_SPEED = 2; //Скорость

  public final static int BALL_RADIUS = 3; //Радиус мячика
  public final static int SPACE_BRICK = 3; // Расстояние между кирпичиками
  public final static int BRICK_ARREA_WIDTH = 5; // Кол-во кирпичей в одном ряду
  public final static int BRICK_ARREA_HEIGHT = 5; // Кол-во кирпичей в одном столбце
  public final static int TOP_BRICK_ARREA = FIELD_TOP + 10; // Положение вверхнего края области кирпичей
  public final static int BRICK_WIDTH = 16; //Ширина кирпичика(в пикселях)
  public final static int BRICK_HEIGHT = 10; // Его высота
}

Два основных класса игровых объектов я описал. Осталось еще привести два класса-помощника в создании нашей с Вами игры. Один из них отображает "дедовский" подход
к реализации тригонометрии на телефонах, на которых отсутствует поддержка типа float. Конечно, если телефон поддерживает конфигурацию CLDC 1.1, то можно
работать напрямую с нужными функциями. Но в этом случае могут возникнуть проблемы при портировании игры, так часть телефонов наверняка имеет CLDC 1.0. Писать же
две разных версии кода не в наших с Вами интересах. Поэтому советую воспользоваться моим способом и ознакомиться со следующим классом:

Цитата
public class Util {

   private static final int[] sin = {
        0,  17,  35,  52,  70,  87, 105, 122, 139, 156,
      174, 191, 208, 225, 242, 259, 276, 292, 309, 326,
      342, 358, 375, 391, 407, 423, 438, 454, 469, 485,
      500, 515, 530, 545, 559, 574, 588, 602, 616, 629,
      643, 656, 669, 682, 695, 707, 719, 731, 743, 755,
      766, 777, 788, 799, 809, 819, 829, 839, 848, 857,
      866, 875, 883, 891, 899, 906, 914, 921, 927, 934,
      940, 946, 951, 956, 961, 966, 970, 974, 978, 982,
      985, 988, 990, 993, 995, 996, 998, 999, 999, 1000,
      1000
   };

   private static final int[] tan = {
        0,  17,  35,  52,  70,  87, 105, 123, 141, 158,
      176, 194, 213, 231, 249, 268, 287, 306, 325, 344,
      364, 384, 404, 424, 445, 466, 488, 510, 532, 554,
      577, 601, 625, 649, 675, 700, 727, 754, 781, 810,
      839, 869, 900, 933, 966, 1000, 1036, 1072, 1111, 1150,
      1192, 1235, 1280, 1327, 1376, 1428, 1483, 1540, 1600, 1664,
      1732, 1804, 1881, 1963, 2050, 2145, 2246, 2356, 2475, 2605,
      2747, 2904, 3078, 3271, 3487, 3732, 4011, 4331, 4705, 5145,
      5671, 6314, 7115, 8144, 9514, 11430, 14301, 19081, 28636, 57290
   };

   public static int getSin(int alpha) {
      if (alpha >= 0 && alpha <= 90) {
         return sin[alpha];
      } else if (alpha > 90 && alpha <= 180) {
         return sin[180 - alpha];
      } else if (alpha > 180 && alpha <= 270) {
         return -sin[alpha - 180];
      } else {
         return -sin[360 - alpha];
      }
   }

   public static int getCos(int alpha) {
      if (alpha >= 0 && alpha <= 90) {
         return sin[90 - alpha];
      } else if (alpha > 90 && alpha <= 180) {
         return -sin[alpha - 90];
      } else if (alpha > 180 && alpha <= 270) {
         return -sin[270 - alpha];
      } else {
         return sin[alpha - 270];
      }
   }

   public static int getX(int x, int y, int alpha) {
      return ((x * getCos(alpha) - y * getSin(alpha)) / 1000);
   }

   public static int getY(int x, int y, int alpha) {
      return (x * getSin(alpha) / 1000) + (y * getCos(alpha) / 1000);
   }

   public static int getAlpha(int x, int y) {
      int alpha = 0;
      if (y == 0) {
         alpha = 90;
      } else {
         long tg = 0;
         try {
            tg = Math.abs(x) * 1000 / Math.abs(y);
         } catch (Exception e) {
            tg = 60000;
         }
         if (tg > tan[tan.length - 1]) {
            alpha = 89;
         } else if (tg == 0) {
            alpha = 0;
         } else {
            int i = 1;
            while (!(tan[i] >= tg && tan[i - 1] < tg)) {
               i++;
            }
            alpha = i;
         }
      }
      if (x < 0 && y > 0) {
         alpha = 360 - alpha;
      }
      if (x < 0 && y < 0) {
         alpha += 180;
      }
      if (x > 0 && y < 0) {
         alpha = 180 - alpha;
      }
      if (y == 0) {
         if (x < 0) {
            alpha = 270;
         } else {
            alpha = 90;
         }
      }
      if (x == 0) {
         if (y < 0) {
            alpha = 180;
         }
      }
      return alpha;
   }
}
Как Вы видите, львиную долю содержимого класса составляет два статических массива, названия которых говорят сами за себя. Наверное, Вы догадались, что это
всего лишь числа после запятой из известной Вам еще из школы таблицы. Методы же данного класса просты и основаны на формулах приведения.
Второй класс-помощник позволит выводить на экран телефона созданным собственноручно шрифтом статистику игры:кол-во жизней и очков. Немного слов о том, как это работает.
В Фотошопе я подготовил картинку, на которой были нарисованы цифры 123....90. В принципе, ввести можно все, что угодно(буквы, цифры, знаки...). Далее,
узнаем смещение в пикселях каждого символа от начала картинки и сформируем следующий массив:

Цитата
private final static short[] DATA = {
      0, 8, 18, 28, 38, 48, 58, 68, 78, 88,98
   };

Далее сформируем строку:

Код
private final static String SYMBOLS = "1234567890";

Зададим расстояние между буквами:

Код
private byte SPACE = 4;


Конструктор класса прост:

Код
public GFont() {

     try {
        img = Image.createImage("/digits.png");

     } catch (Exception ex) {

     }
  }

где digits.png - файл с нашими символами.
Два основных метода класса GFont:

Код
public int getWidth(String str) {
     str = str.toUpperCase();
     int w = 0;
     for (int i = 0; i < str.length(); i++) {
        try {
           int pos = SYMBOLS.indexOf(str.charAt(i));
           w += (DATA[pos + 1] - DATA[pos]);
        } catch (Exception ex) {
           w += SPACE;
        }
        w++;
     }
     return w;
  }


  public void drawString(Graphics g, String str, int x, int y, byte align) {

        str = str.toUpperCase();
        int w = getWidth(str);
        if (align == RIGHT) x -= w;
        if (align == CENTER) x -= w >> 1;
        for (int i = 0; i < str.length(); i++) {
           try {
              int pos = SYMBOLS.indexOf(str.charAt(i));
              int _w = (DATA[pos + 1] - DATA[pos]);

              g.setClip(x, y, _w, img.getHeight());
              g.drawImage(img, x - DATA[pos], y, g.TOP | g.LEFT);

              x += _w;
           }
           catch (Exception ex) {
              x += SPACE;
              System.out.println("!!!");
           }
           x++;
        }

     }

Первый из них возвращает длину передаваемой строки в пикселях, а второй(самый главный) - отрисовывает нужную строку на передаваемом Graphics из точки х и у с привязкой align
Таким образом мы рассмотрели вспомогательные классы, которые мы будем использовать в нашем с Вами игре. Перейдем непосредственно к внутренней структуре игры:

Любое приложение под J2ME должно содержать как минимум один класс, который должен расширять(extends) MIDlet. Sun Microsуstems использует суффикс "let" для обозначения раличных типов программ, создаваемых с помощью Java. Вспомните, апплеты, корелеты и теперь мидлеты. Как я уже сказал выше, каждый мидлет должен наследоваться от стандартного класса, который расположен в пакете javax.microedition.midlet. Три метода этого класса крайне важны для разработки мидлета:
- startApp() - метод, выполняющийся при запуске мидлета
- pauseApp() - приостановка мидлета
- destroyApp() - метод, выполняющийся при разрушении мидлета

По сути, эти три метода отражают три состояния, в которых может находиться приложение. Все они составляют так называемый "жизненный цикл" мидлета. Следует также сказать, что в течение жизненного цикла мидлет может входить и выходить в различные состояния несколько раз, но, попав в состояние Destroyed, он уже не сможет вернуться назад.

Наш класс ArcanoidMidlet в соответствии с вышесказанным примет следующий вид:

Код
public class ArcanoidMidlet extends MIDlet {
  static ArcanoidMidlet instance;
  ArcanoidCanvas displayable = null;

  public ArcanoidMidlet() {
     instance = this;
  }

  public void startApp() {
     if (displayable == null) {
        displayable = new ArcanoidCanvas();
        Display.getDisplay(this).setCurrent(displayable);
     }
  }

  public void pauseApp() {
  }

  public void destroyApp(boolean unconditional) {
  }

  public static void quitApp() {
     instance.destroyApp(true);
     instance.notifyDestroyed();
     instance = null;
  }

}


Чтобы двигаться дальше следует уделить внимание еще одной важной концепции разработки мидлетов. Обратите внимание, что при запуске игры(метод startApp() ) вызывается конструкция Display.getDisplay(this).setCurrent(displayable)
Класс Display представляет собой менеджер экрана мобильного устройства. У Вас нет необходимости создавать объект типа данного класса. У мидлета он уже имеется. Единственное, что потребуется от Вас, так это всего лишь получить ссылку на него Display.getDisplay(this) Чтобы закончить описание вышеуказанной конструкции следует рассмотреть еще один класс, которому мы уделим более пристальное внимание чуть позже. Класс javax.microedition.lcdui.Canvas представляет собой абстрактную поверхность для рисования. В связке со специальным механизмом данный класс зачастую становится едва ли не важнейшим для понимания сути разработки игр. Таким образом получив ссылку на Display и вызвав метод setCurrent(displayable), которому в качестве параметра мы передали ссылку на переопределенный нами класс Canvas (еще немножко потерпите и будем рассматривать его), мы установили соответствие между "дисплеем" и "канвасом". Чувствуете? Медленно, но верно мы подходим к самому важному...

Давайте задумаемся, что есть такое игра. Игра - это прежде всего процесс, то есть действия повторяющиеся с течением времени. Появляется закономерный вопрос. Что позволит нам обеспечить эту повторяемость? Какой механизм для этого использовать?
Ответ прост. Использовать потоки. Их основа - класс java.lang.Thread . При этом есть два способа создания потоков. Первый из них - просто унаследоваться от класса потоков и переопределить его метод run() (о нем позже). Второй способ интересней(о нем я уже упоминал выше). Он заключается в реализации интерфейса Runnable. В чем интерес, скажете Вы? Хитрость заключается в том, что унаследовав просто "тред", Вы делаете его единственным родителем Вашего класса. Пойдя же по второму пути Вы оставляете за собой возможность унаследовать Ваш класс от чего угодно, например, от Canvas'а, имея при этом возможность использовать поток. Улавливаете? Это как раз то, что нам нужно... Дабы не обременять Вас теорией скажу, что реализация интерфейса Runnable дает нам возможность переопределять метод run() , который станет "сердцем" и "мотором" нашей игры. Но "мотор нужно завести" скажете Вы. И будете правы.
И для этого нам понадобится все тот же Thread. Думаю, что теперь все необходимые подготовительные работы сделаны, можно переходить к рассмотрению самого главного класса программы.

Итак. Нам необходим класс, который брал бы на себя обязанности отрисовки игровой графики + содержал бы в себе всю игровую логику. Что будем делать? Опишим класс ArcanoidCanvas, причем сделаем это следующим образом:
class ArcanoidCanvas extends Canvas implements Runnable. В контексте вышесказанного, думаю вопросов не возникнет...
Какие будут поля у этого класса? Вот они:

Код

  private boolean threadStopped = false; //Флаг прекращения работы основного потока игры
  private GFont font; //Наш рисованный шрифт
  private Brick[][] brickArrea = new Brick[Data.BRICK_ARREA_HEIGHT][Data.BRICK_ARREA_WIDTH]; //Массив кирпичиков. Уже знакомый нам класс
  private boolean initBrickArrea = false; // Флаг инициализации области кирпичиков
  private int racketX = 0; // Положение по оси Х битки
  private int racketY = 0; //Положение по оси У
  private int racketWidth = 0; // Ширина битки
  private byte racketState = 0; // Состояние ракетки, определяемое константами ниже
  private final static byte RACKET_STOP = 0; //Битка стоит на месте
  private final static byte RACKET_LEFT = 1; //Битка движется влево
  private final static byte RACKET_RIGHT = 2; //Битка движется вправо

  private final static byte RACKET_HALF = 0; // Битка уменьшается вдвое
  private final static byte RACKET_NORMAL = 1; // Нормальный размер битки
  private final static byte RACKET_DOUBLE = 2; //Увеличенный размер битки

  private final static int HIGH_BALL_SPEED = 4; //Повышенная скорость мячика
  private final static int NORMAL_BALL_SPEED = 3; //Нормальная скорость
  private final static int LOW_BALL_SPEED = 2; //Медленный мяч

  private long time = 0;

// Пункты главного меню
  private final String[] menuMain = {
        "New Game",
        "Exit"
  };

//Пункты меню паузы
  private final String[] menuPause = {
        "Resume",
        "Quit"
  };

//Положение в меню
  private int menuPos = 0;


 //Начальный размер битки поставлен в нормальный
  private static byte racketSizeState = RACKET_NORMAL;

  private int ballX = 0; //Иксовая координата мячика
  private int ballY = 0; //Игриковая
  private int ballSpeed = NORMAL_BALL_SPEED; //Скорость мяча. По-умолчанию она нормальная
  private int ballAlpha = 0; // Угол полета мяча
  private int livesNum = 3; //Кол-во жизней
  private int pointsNum = 0; //Кол-во очков

  private byte ballState = 0; //Состояние мяча, определямое константами ниже
  private final static byte BALL_INIT = 0; //Инициализация мяча
  private final static byte BALL_FLY = 1; // Полет мяча

//Состояния игры:
  private final byte STATE_LOGO = 0; //Состояние "Логотип"
  private final byte STATE_MENU = 1; //Состояние "Главное меню"
  private final byte STATE_GAME = 2; //Состояние "Игра"
  private final byte STATE_GAME_WIN = 3; //Состояние "Вы выиграли"
  private final byte STATE_GAME_LOSE = 4; //Состояние "Вы проиграли"
  private final byte STATE_MENU_PAUSE = 5; // Состояние "Меню пауза"

  private byte gameState = STATE_LOGO; // Текущее состояние игры. По-умолчанию - состояние "Логотип"

  private final static int KEY_SOFTKEY1 = -6; //Код левой софт-клавиши(для SE). Для моторол(-21 или иногда  21)
  private final static int KEY_SOFTKEY2 = -7; //Код правой софт-клавиши(для SE). Для моторол (-22 или иногда 22)

  private Random rand = new Random(); //Генератор случайных чисел

Приведу конструктор класса:

Код

     public ArcanoidCanvas() {
     setFullScreenMode(true);
     initData();
     font = new GFont();
     (new Thread(this)).start();
     initBrickArrea = false;
     time = System.currentTimeMillis();
  }

Что в нем делается? Вызов метода setFullScreenMode(true) с передаваемым параметром true говорит, что мы переводим приложение в полноэкранный режим, думаю Вы уже знакомы с эффектом работы данной функции(FullJava помните?). Так. Далее происходит начальная инициализация компонентов игры(рассмотрим ниже). Далее создаем наш шрифт. И самое интересное..."Запускаем мотор" :). После этого говорим, что необходимо сделать инициализацию области кирпичей(initBrickArrea = false;) и засекаем время начала игры. Смотрим на метод initData():
Код
private void initData() {

     racketX = (Data.FIELD_WIDTH / 2);
     racketY = Data.FIELD_HEIGHT;
     racketState = RACKET_STOP;
     racketSizeState = RACKET_NORMAL;
     handleRacketSize();
     ballX = (Data.FIELD_WIDTH / 2);
     ballY = (Data.FIELD_HEIGHT - Data.BALL_RADIUS);
     ballSpeed = NORMAL_BALL_SPEED;
     ballAlpha = 0;
     ballState = BALL_INIT;
     for (int i = 0; i < Data.BRICK_ARREA_HEIGHT; ++i)
        for (int j = 0; j < Data.BRICK_ARREA_WIDTH; ++j) {
           if (initBrickArrea &&
               brickArrea[i][j].getTypeBrick() == Brick.BONUS &&
               brickArrea[i][j].getBonus().isFlying()) {
              brickArrea[i][j].getBonus().setNotFlying();
           }
        }

  }

и вспоминаем, что делали ранее(классы Brick и Bonus)
После того, как "мотор" запущен, начинает выполняться метод run(). Рассмотрим его:
Код

public void run() {
     while (!threadStopped) {

        handle();
        repaint();
        serviceRepaints();
        Thread.currentThread().yield();

        try {
           Thread.currentThread().sleep(25);
        }
        catch (Exception ex) {

        }
     }
     ArcanoidMidlet.quitApp();
  }

Это "классическая" реализация игры. Наверное, в 97 случаях из 100 все игры, которые существуют на рынке имеют похожую реализацию данного метода. Конечно, бывают более совершенные реализации. Но про них я расскажу в своих последующих статьях. "Классика" есть "классика". Приложение закончит свою работу с прекращением работы метода run() . Но нам нужен цикл. Для этого мы и помещаем все в цикл while (!threadStopped).Теперь, чтобы прекратить игру нужно только поставить флаг threadStopped в true. Внутри цикла вызываются основные методы игры: handle() - игровая логика, "парочка" repaint() и serviceRepaints(), отвечающие за перерисовку графики, Thread.currentThread().yield() - "говорим" текущему потоку временно прекратить свою работу, чтобы дать отработать другим потокам. Нам это нужно, чтобы игра своевременно реагировала на нажатия кнопок на телефоне. Этому же служит и конструкция:
Код

        try {
           Thread.currentThread().sleep(25);
        }
        catch (Exception ex) {
        }

где мы "говорим" текущему потоку замереть на 0,25 с.
Последняя строка в нашем "моторе" ArcanoidMidlet.quitApp(), в которую мы попадем только, когда захотим закончить игру. Вспомните, класс нашего мидлета. Вспомнили? А помните, я рассказывал про состояния мидлета. После этого мидлет перейдет в состояние destroyed.
Я не вижу смысла приводить полностью весь код данного класса, так как к статье я прилагаю исходники данного проекта, расскажу только вкратце о главном. Метод handle() содержит, как я уже говорил выше, игровую логику приложения. Идет проверка столкновения мяча со стенками, с биткой, происходит проверка того, летит ли бонус, словлен ли он игроком. Вызывается метод checkCollision() для проверки столкновения мяча с кирпичами. Также при столкновении мяча с биткой происходит расчет угла отражения мяча в зависимости от того, какой частью битки был отбит мячик. Более детальный обзор этих методов я смогу дать, отвечая на Ваши вопросы. Хочу напоследок остановиться на двух важных методах, присутствующих в нашем классе. Помните метод repaint()? Вызов данного метода вызывает метод paint() нашего Canvas'a. Данный метод в зависимости от состояний игры(меню, игра, лого...) отрисовывает нужную графику. Методы эти несложные, думаю разберетесь. Осталось рассмотреть еще метод keyPressed(int keyCode), отвечающий за отработку нажатия клавиш. Вернее сказать, таких методов 3. "Кипресд" срабатывает, когда мы нажали и держим клавишу, keyReleased(int keyCode), когда мы отпускаем клавишу, keyRepeated(int keyCode) - при повторяющихся нажатиях. Как Вы видите, данные методы получают в качестве параметра код клавиши. Помните, в самом начале среди полей класса мы задавали собственноручно коды для софт-клавиш? В приложении каждая клавиша имеет свой код, и по нему можно отследить нажатие именно на нее. Но представляете, как это утомительно, хранить коды всех клавиш. Поэтому для упрощения работы с клавишами есть более простой механизм. Пример из нашей программы:
Код

             int action = 0;
              try {
                 action = getGameAction(keyCode);
              }
              catch (Exception ex) {

              }

              switch (action) {
                 case UP:
                 ....
                  break;
                 case DOWN:
                 ....
                 break;
                 case FIRE:
                 ....
                    break;
              }
Смысл этого участка кода заключается в том, что клавишам по их коду ставится в соответствие action и уже по нему, используя константы "Канваса" (UP, DOWN, FIRE) можно совершать нужные нам действия. Прелесть данного метода заключается в том, что такой код будет работать универсально на любом телефоне и Вам не нужно знать какие коды соответствуют нажатым клавишам. Единственное, что софт-клавиши обработать таким образом не получится. Поэтому придеться хранить отдельно их коды. Метод keyRepeated(int keycode) в нашей игре не используется, однако используется метод keyReleased(int keyCode), который я использую для остановки битки(racketState = RACKET_STOP)

Как Вы видите, 3 основных метода игры, а именно handle(), paint(Graphics g), keyPressed(int code) работают в строгой зависимости от того состояния, в котором находится игра. Поэтому такую реализацию игры иногда еще называют "state machine"(машиной состояний). Существуют различные мнения по поводу такого подхода к созданию игр. Одни считают, что это больше похоже на процедурное программирование и говорят, что тем самым унижаются все ООП достоинства языка Java, другие говорят, что мы имеем дело все-таки с J2ME и ресурсы у нас ограничены. Я думаю, что правы все. Я видел различные реализации игр. Я видел, как человек переделывал игры под стейт-машину из-за слишком большого кол-ва классов и неработоспособности приложения на некоторых телефонах, видел всю несостоятельность попытки автоматизировать разработку и портирование игр под огромный модельный ряд телефонов только из-за того, что некоторые люди не понимают, что
Цитата
"само никогда ничего не делается"
, видел и , надеюсь, увижу многое...
В заключении хотелось бы сказать, что несмотря на свою кажующуюся простоту и примитивность, данная сфера разработок программного обеспечения имеет огромное будующее, так как число обладателей мобильных телефонов растет, как и ростут потребности людей в удовлетворении своих ежедневных желаний развлечения и удовольствия. Не за горами те дни, когда возможности мобильных устройств станут соизмеримы с современными ПК, когда мобильные приложения выйдут на новый более качественный виток своего развития. Ежегодный приток денежных масс, повышенный интерес, креативность и изменчивость направлений - вот основные аргументы, позволяющие с уверенностью говорить, что мобильные развлечения себя еще покажут. На что и надеется Ваш скромный слуга :)

P.S.
Изначально статья задумывалась как FAQ для начинающих, дабы помочь им в написании своей первой простенькой игры. Однако по ходу работы автор незаметным для себя способом несколько отошел от чисто технической стороны и пристал к берегу философских наблюдений за развитием интересующей его сферы деятельности, в связи с чем несколько сократились пояснительные элементы для основного класса примера. Однако автор искренне уверен, что прилагаемые к статье исходники смогут помочь всем жаждущим в освоении азов программирования мидлетов. В чем он собирается им всячески помогать.

P.P.S.
Хотелось бы сказать, что данный мидлет "заточен" под E398. Однако внеся минимальные изменения в класс Data и поменяв константы софт-клавиш(если Вы портируете игру под телефоны, отличные от Моторола), Вы без труда сможете адаптировать приложение под любой другой модельный ряд телефонов.


Прикрепленный файл Arcanoid.rar   ( 37.53 килобайт ) Кол-во скачиваний: 846
Прикрепленное изображение
Прикрепленный файл Arcanoid.rar   ( 37.53 килобайт ) Кол-во скачиваний: 846
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Ectar
сообщение 9.11.2004, 15:29


Мотоманьяк
*****

Группа: Почётные мотофаны
Сообщений: 532
Регистрация: 23.3.2004
Из: Canada
Пользователь №: 2 465
Модель телефона: Motorola V551, E1000
Прошивка: R472_G_08.18.55R, 80.3F.36I (0.5.F.1)

Рейтинг: 139



JenFA
Цитата
Этот API есть в A830 A835 C370/C450/C550 E380. Всё
Скачать - www.motocoder.com (Motorola Java SDK)...

Тоесть простым добавление нужных пекеджей этот вопрос не решается ? Тоесть это реализация на уровне виртуальной машины ?
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
max.wiz
сообщение 9.11.2004, 16:09


Мастер
****

Группа: Пользователи
Сообщений: 206
Регистрация: 14.9.2004
Из: МО, г. Наро-Фоминск
Пользователь №: 12 584
Модель телефона: V300 -> V635 -> Z6
Прошивка: ---

Рейтинг: 42.5



Цитата
Тоесть простым добавление нужных пекеджей этот вопрос не решается ? Тоесть это реализация на уровне виртуальной машины ?


1) Дык надо добавить класс-файлы моторолы в JDK;
2) Это реализация на уровне "железа" (native), поэтому компилить можно и в Билдере, а вот тестить лучше под мотороловским эмулятором.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Ectar
сообщение 10.11.2004, 16:46


Мотоманьяк
*****

Группа: Почётные мотофаны
Сообщений: 532
Регистрация: 23.3.2004
Из: Canada
Пользователь №: 2 465
Модель телефона: Motorola V551, E1000
Прошивка: R472_G_08.18.55R, 80.3F.36I (0.5.F.1)

Рейтинг: 139



чет я не все понял, ладно сам проверю и расскажу....
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
yurique
сообщение 5.3.2005, 1:42


Мастер
****

Группа: Пользователи
Сообщений: 244
Регистрация: 4.1.2005
Из: Чернигов/Киев, Украина
Пользователь №: 32 130
Модель телефона: HTC Hero
Прошивка: 1.5

Рейтинг: 180



Цитата
И еще вопрос - что лучше юзать, SunONE Mobile Edition (сейчас качаю, 23 Мб, кому нужен - http://www.yashka.dp.ua/java/files/ffj_me_win32.exe), или же JBuilder 5? Мне самое важное - удобная и не слишком нагруженная лишними функциями среда программирования, в которой было бы удобно программить (подсветка синтаксиса) и собирать готовый .jar без лишних телодвижений, а также удобная работа с эмулятором из Motorola SDK. На выбор у меня как раз JBuilder и SunONE, и что-то я в сторону последнего склоняюсь... Меньше занимает, а я люблю небольшие проги, они как-то удобнее


Я сам юзаю (и рекомендую B) ) Eclipse. По-крайней мере для разработки под j2me лучше не придумаешь. Конечно после установки соответствующего плагина - eclipse.me... Работает с wireless toolkit'ами... Есть всё что нужно. Компилит на ходу (и ошибки соответственно сразу показывает..) Работа с jar'ами тоже прозрачная... В общем кому интересно - сюда www.eclipse.org.. Единственный минус - это 80-метровый дистрибутив...

ЗЫ: JavaONE - как по мне слабоват... а JBuilder - слишком много для j2ME :)
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 14.11.2006, 12:50


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



Объединил старую и новую темы. Надеюсь, начинающие ява-кодеры смогут найти здесь для себя что-нибудь ценное. Возможно, перенесу сюда сообщения из похожих тем, чтобы максимально сконцентрировать здесь информацию по разработке игр. Просьба к разработчикам, если есть конечно желание, отписываться здесь, если сочтете нужным.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 16.11.2006, 16:54


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Уберите закрепленность с первого сообщения, а то на каждой странице оно занимает 95%. Листать неудобно.

Кстати я бы хотел услышать мнение про то надо ли вообще пользоваться System.gc() (или Runtime эквивалентом, не важно).

Я делаю его каждый кадр - не тормозит, и память не меняется.
Если каждый кадр не делать, то она безит до нуля, потом происходит автоматический gc() и она становаиться правильно, потом тут же вниз бежит.

Поведайте про дефрагментацию heap-а. на сколько реально на нее натнуться если у меня за час игры раз 30 происходит выгрузка и загрузка кусков по 300 кб, но создаются не одним масивом, но почти подряд, по-моему.

Спасибо, хороший топик!
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 16.11.2006, 19:34


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS, ты думаешь, что если перестанешь сам вызывать Garbage Collector, то он не будет никогда вызываться? KVM сама будет его вызывать, когда будет на то необходимость. Еще раз повторяю. Единственный способ в Яве удалить объект - перестать на него ссылаться. Далее сборщик мусора анализирует объекты. Если ссылок на него нет, то объект удаляется из памяти. То, что ты вызываешь его в каждом кадре - поверь, не сейчас, так дальше будет весьма и весьма ощутимо.
Что касается фрагментации... С этой проблемой я столкнулся, когда попытался портировать свой проект(на тот момент разработка велась в основном для С650) для Е398. В момент загрузки ресурсов уровня приложение висло. Лог мидвея показал, что возникает OutOfMemoryException. Как так. Памяти свободно более 120 кб на момент загрузки очередной порции данных, грузится картинка размером 1 кб максимум, а памяти нет? Странно...В одной из тем на motocoder.com официально моторолой было признано...да, есть проблемы с фрагментацией памяти...Ничего не поделаешь. Пришлось многое переделывать. Основной совет, не держать в памяти большие имеджи(сплэши, лого, и т.д). Они "едят" очень много. Стараться создавать как можно меньше объектов...Вот так...
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 17.11.2006, 5:29


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Stranger @ Пятница, 17 Ноября 2006, 1:34)
ZaharS, ты думаешь, что если перестанешь сам вызывать Garbage Collector, то он не будет никогда вызываться? KVM сама будет его вызывать, когда будет на то необходимость. Еще раз повторяю. Единственный способ в Яве удалить объект - перестать на него ссылаться. Далее сборщик мусора анализирует объекты. Если ссылок на него нет, то объект удаляется из памяти. То, что ты вызываешь его в каждом кадре - поверь, не сейчас, так дальше будет весьма и весьма ощутимо.


Совсем написаным абсолютно согласен - кроме последне строчки.
У меня System.gc() в отладочных целях каждый кадр и ничего не тормозит на E398.

То что gc() вызывается при нехватки памяти наглядно видно если ее каждый кард выводить, она бежит до нуля, потому происходит gc() и снова большая.
>ZaharS, ты думаешь, что если перестанешь сам вызывать Garbage Collector, то он не будет никогда вызываться?
Так что я так не думал =)
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 20.11.2006, 13:21


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Как Вы думаете, не лучше ли откааться от использования, привыйных для написания под PC, access-оров, а просто делать члены public. Тем более, что в данном коде проверок set() не делают, я конечно пнимаю, что возникнут сложности если эти проверки нужны. Получиться код меньше и чуть читабельнее.


Как лучше обрабатывать ошибки при всяких случаях - типа загрузка картинки неудалась и т.п.?
Пропускать через себя IOException выше или catch()-ить его и возвращать false или что-то предпринимать. Из соображений красоты и стойкости кода.


На скольких телефонах есть приостановка игр? ( к теме о pauseApp() )

>>>Thread.currentThread().yield() - "говорим" текущему потоку временно прекратить свою работу, чтобы дать отработать другим потокам.
>>>Нам это нужно, чтобы игра своевременно реагировала на нажатия кнопок на телефоне.


На сколько это нужно? Есть ли примеры, где, если я это не запускаю, то что-то теряю?


И самый главный вопрос, что писать в pauseApp(), чтобы приложение корректно сворачивалось? Я должен что-то приостановить ( Thread), должен что-то грузить после восстановления заново или как? У меня сейчас как и во многих играх на E398 восстановление заставляет тел "отказаться" от явы, до блежайшего выключения-включения, которое прохоит почему-то долго. ( платформа 4X, от монстров по-моему не зависит )
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 21.11.2006, 8:11


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS,

по поводу public. В принципе, я так и делаю, мобильная ява на то и мобильная, правила игры там несколько другие...
По поводу обработки исключений...в идеале код должен быть написан так, чтобы не оставалось исключений, которые не были бы отловлены. Тогда будут достигнуты "красота и стойкость кода". Однако у меня до сих пор имеются проблемы при отловке OutOfMemoryException при загрузке ресурсов одного из уровней моей игры. Ситуация такая, что у меня из-за преславутой фрагментации не загружаются буквально 2-3 тайла. Моя задумка такова, что загрузку уровня заканчивать все равно, и пусть в игре не будут отрисованы те тайлы, проблем из этого думаю не будет...Однако, то ли я чего-то не знаю, то ли делаю неправильно, но OutOfMemoryException остается пока-что неуловимым.
Что касается сворачивания мидлета. Я не использую pauseApp()... В своей статье я не описал механизм, который я использую, однако в исходниках он есть. Посмотри в Канвасе есть два метода showNotify(), hideNotify(). При внешнем событии мидлет уйдет в паузу, но перед этим будет вызван метод hideNotify(), в котором можно грамотно поставить игру на паузу, showNotify() сработает при возвращении мидлету фокуса от внешнего события. Однако не на всех телефонах эти два метода работают. Если кому-то интересно, могу написать еще статейку о том, как можно обойти эти трудности + примеры кода...
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 22.11.2006, 12:57


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Stranger спасибо.

Посмотрел исходник Arcanoid\src, т.е. для корректного сворачивания вовсе не надо что либо делать в Mitlet::pauseApp() ?

Я попробую добавить такого рода код в свой мидлет и потестю. Вопрос - при нажатии красной кнопки на E398 программа имеет возможность что-то делать ( всмысле worms даже на экран успевают вывести "Пауза"), и сколько время отведено на отклик мидлета? Что если я вообще сделаю while(1); в hideNotify() и вообще откажусь тем самым из нее выходить?
Что проиходит с ходом выполнения мидлета при паузе через красную кнопку, и почему он падает если не перегружает hideNotify(), крутился бы в холостую или заморощился полностью, но почему они все падают и уводят яву на теле в даун до перезагрузки?
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 23.11.2006, 9:49


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



У меня так с паузой и не получилось. Жму карсную кнопку, игра пишет пауза, выскакивает меню. Жму возобновить, надпись пауза ( теперь любой кнпкой должно быть продолжение, но тут же все закрывается, а значек явы остается. Причем по перезагрузки ява не работает.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 23.11.2006, 18:51


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS,
не знаю, может ты что-то делаешь не так? Это только с твоей игрой или же с другими наблюдается такая же картина? Возьми любую игру от геймлофта. Если и с ней то же самое, значит, это издержки прошивок 4хR серии. Так при тестировании это точно один из пунктов. А зная назойливость QA даже нашей фирмы, могу предположить, что в геймлофте с этим еще "лучше".
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 24.11.2006, 4:11


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Stranger @ Пятница, 24 Ноября 2006, 0:51)
Возьми любую игру от геймлофта. Если и с ней то же самое, значит, это издержки прошивок 4хR серии.

Короче Midnight Pool от GameLoft ведет себя Абсолютно так же.
Но твой код сворачиваетяс нормально ( в чем подвох? ), опера и megasender тоже отлично сворачиваются.
Платформа действительно 45, и я заметил что это появилось кодга перешел на 4Х. НО я думал это просто кривонаписаны мидлеты, раз опера и некоторые другие нормально сворачиваются и главное разворачиваются. А теперь сам пишу кривые мидлеты =)

Как бы понять почему такое происходит...
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 24.11.2006, 16:55


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



А сейчас вообще маразм - при развертывании приложение запускается заново ( причем быстро - без белого экрана ). При этом память от прошлого экземпляра не возвращается! И так можно делать пока память совсем не кончиться.

PS.
Убрал из своего run()
serviceRepaints();
Thread.currentThread().yield();

И тормозить стало меньше. И без них все работало, от добавления только тормоза появились.
Если без них все работает, то надо ли их запускать (я понимаю зачем они, но без них тоже все ок и даже лучше )
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 24.11.2006, 20:34


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS,
ну никто и не говорит, что следующие методы нужно вызывать в каждой игре :) Для одних телефонов - это способ для прибавки производительности, для других - необходимость, иначе игры просто не будут работать. В портингах для моторов их чаще всего нет. Все зависит от способа реализации игры. Если ты используешь GameCanvas, то никакой serviceRepaints() вызывать не надо. Там существуют свои методы...Поэтому...почитай доки, узнай точно, что выполняют эти функции и решай сам, использовать ли их тебе или нет. Каждый ведь выбирает сам, что себе делать. Не так ли :) ?
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 25.11.2006, 7:37


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Я не использую GameCanvas - потому что он у него нет преимуществ. Кнопки по getkeyStates() или что-то такое не считываются ( только джойстик и некие ABCD, к которым у меня на E398 нет биндов). РПоверил на своем теле ( писал программку ) нормально нработать с Canvas.KEY_NUM0 он на моем теле не работает! Никакие getGameAction(code) тоже не помогают избежать многозначности. ПРишлось делать как в 99% игр ( я декомпилил ), делать через Canvas.keyPressed(int code).
Но это отдельная тема.

С паузой какой-то катаклизм. Какая-то игра от Gameloft сворачивается, какие-то падают как и моя. Декомпельну, постараюст понять обфусканный код, чего там отличается...
О результатах отпишусь.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 23.1.2007, 14:36


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Ну в общем я так и не понял в чем проблема, но если кто-то подскажет, почему некорретно разворачивается у меня игра, буду очень благодарен. Исходный код тут ( в конце первого поста ):
https://motofan.ru/board/index.php?showtopic=83864&st=225


Stranger, на тебя надежда =)

Stranger:Конечно, я постараюсь помочь...только чуть позже...пока нет времени

Сообщение отредактировал Stranger - 27.1.2007, 9:00
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 29.1.2007, 9:26


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Stranger большое спасибо, буду ждать.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Грустный
сообщение 30.1.2007, 1:12


Dum vivimus vivamus
***

Группа: Пользователи
Сообщений: 102
Регистрация: 23.6.2006
Пользователь №: 88 814
Модель телефона: V180, V360

Рейтинг: 29



Цитата(ZaharS @ Суббота, 25 Ноября 2006, 2:55)
А сейчас вообще маразм - при развертывании приложение запускается заново ( причем быстро - без белого экрана ). При этом память от прошлого экземпляра не возвращается! И так можно делать пока память совсем не кончиться.

На motodev есть статья на эту тему: "Interaction of the MIDlet Life Cycle and Host Execution Environment".
Прикрепленное изображение
Т.е. в startApp() не надо повторно инициализировать MainCanvas.
Типа:
Код
if (null == mCanvas){
     mCanvas = new MainCanvas();
     mCanvas.Init(this);
}

Тогда при развертывании будет надпись "пауза".
(Проверял на V360)
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 30.1.2007, 8:08


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



Да, действительно, метод startApp() вызывается в том случае, если мидлет запускается впервые или же приложение восстанавливается после паузы. Однако я не совсем понял фразы
Цитата
Тогда при развертывании будет надпись "пауза"
...Чтобы эта надпись появилась, программисту нужно самому предусмотреть возможность ее появления... Не факт, что, если в момент какого-то входящего внешнего события, когда в приложении работает какой-нибудь активный поток, приложение свернется в паузу, то оно не продолжит свое выполнение. Здесь необходимо правильно построить логику программы.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 30.1.2007, 11:47


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Stranger @ Вторник, 30 Января 2007, 13:08)
..Чтобы эта надпись появилась, программисту нужно самому предусмотреть возможность ее появления... Не факт, что, если в момент какого-то входящего внешнего события, когда в приложении работает какой-нибудь активный поток, приложение свернется в паузу, то оно не продолжит свое выполнение. Здесь необходимо правильно построить логику программы.
*


Спасибо всем, все теперь работает.

Stranger, Про надпись он имал ввиду именно в моем когде, я там это все сделал, и жду кнопки дл продолжения работы. Короче дабавил флаг запуска startApp() первый раз или нет и все отлично стало.
Всем спасибо.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 8.3.2007, 18:01


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Если кому инетресно вот статья
Оптимизация J2ME приложений
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 8.3.2007, 20:57


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS, молодец, классную статью откопал. Ребята действительно поделились очень ценной информацией. Очень часто, чтобы прочитать все это, приходилось рыскать по форумам и собирать данные буквально по крохам. Складывается ощущение, что все конторы, занимающиеся разработкой и портированием под J2ME, двигаются одними и теми же дорожками. Все стараются максимально уменьшить время портирования игр. Тестируются разные системы портирования. Мы уже работали и даже еще, кажется, работаем с Celsius. Параллельно сами пишем свою систему портирования. В частности передо мной была поставлена задача, очень похожая на ту, что описана в статье. Необходимо было написать утилиту, которой бы давался на вход набор картинок, она бы находила бы среди них одинаковые участки, вырезала бы все совпадения, и в конце концов формировала бы оптимальную по площади картинку и отдельный класс для J2ME с константами для парсинга и вывода изображений. Также необходимо было производить поиск один. зон с учетом flip(ver. & hor.), а также rotation(90, 180, 270). И действительно правы ребята, такие утилиты оптимизации изображений дают очень ощутимый прирост. Так, например, вот что могло бы получиться из набора 8 картинок(каждая 14х31 пиксель) с разными видами трансформаций. Прикрепленное изображениеИсходные картинки имели размер 5 кб, конечная же картинка занимает менее 1 кб. Так что, все развиваются очень одинаково...Разве что западные конторы думаю от нас уже далеко впереди...И с этим ничего не поделать, к сожаленью....

Сообщение отредактировал Stranger - 8.3.2007, 20:59
Прикрепленное изображение
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 9.3.2007, 17:05


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



У меня возникли 2 вопроса:

0)
Возник вопрос как поток завершить? (Без исползования своих флагов).
Нужно остаться в пределах CLDC 1.0 ( в CLDC 1.1 есть Thread.interrupt() ).

1)
Если я напишу
Thread h = new Thread(this);
h.start();
h = new Thread(this);
h.start();

То будут запущенны 2 разных процесса и каждый будет выполнять одну функцию this.run() или каждый объект Runnable принадлижит не более чем одному процессу?




А по поводу оптимизации небольшой offtopic - когда же настанет время, что можно будет не шибко думать о том, чтобы до безобразия ужать размер, кол-во цветов и используемой памяти... Сейчас в j2me все реально очень жутко сжато делается имхо. Прям жутко.

Сообщение отредактировал ZaharS - 9.3.2007, 17:12
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 10.3.2007, 9:43


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS,
по поводу 0)
по идее, хорошо спроектированный код должен всегда отзываться на метод interrupt(). Однако переходить на конфигурацию 1.1 только из-за доступа к этому методу,думаю, не стоит. Поток, в котором метод run() возвращает управление(то ли он естественно завершился, то ли ты вызвал return), всегда завершается. Поэтому, без использования "своих флагов" никак.
По поводу 1)
Когда ты пишешь
Код
Thread h = new Thread(this);
, то ты ,во-первых, конструируешь новый объект Thread, использующий метод run() объекта this, далее ты присваиваешь ссылку на вновь созданный объект переменной h. Далее ты запускаешь поток на выполнение.
Когда ты вновь пишешь
Код
h = new Thread(this);
h.start();

то происходит то же самое, только этот же run() будет выполнять еще один поток. Здесь должны быть включены механизмы синхронизации. Иначе возможны потери данных.

Сообщение отредактировал Stranger - 10.3.2007, 9:55
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 10.3.2007, 11:01


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Stranger @ Сегодня, 15:43)

то происходит то же самое, только этот же run() будет выполнять еще один поток. Здесь должны быть включены механизмы синхронизации. Иначе возможны потери данных.

Я просто к тому, как относиться gc() к тому, что экземпляр класа Thread перестал существовать ( например при выходе из зоны видимости ). Спасибо, поняно по этому вопросу.


Цитата(Stranger @ Сегодня, 15:43)

Поэтому, без использования "своих флагов" никак.

Я бы их использовал, но просто в нем выполняются такие вещи как соединение по http, они локают поток и обрабатывать флаги он не может. Причем было бы ничего страшного, если другой поток его прервал и послал другой http запрос, но прервать поток получается никак нельзя, пока он сам не проверит просят ил его прекратиться, это не есть удобно, а с тамими вещами как http get/post запросы это вообще всю фичу убивает.
Может я что-то не правильно понимаю?

PS. Дейстивительно же что у многих телеофонов одновременно может быть не более одного соединения http ?
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 10.3.2007, 21:02


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



ZaharS, к сожаленью, у меня нет большого опыта работы с http на яве, поэтому ничего по этому поводу я тебе подсказать не могу.
Я не имею просто четкой картины того, что тебе надо. Объясни четко, в чем проблема, тогда, думаю, я или кто-нибудь другой постараются тебе помочь
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 11.3.2007, 4:04


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Stranger @ Сегодня, 3:02)

Я не имею просто четкой картины того, что тебе надо. Объясни четко, в чем проблема, тогда, думаю, я или кто-нибудь другой постараются тебе помочь


Ага, наверное путано объяснил. Короче:
Есть поток, который общается через http.
Нужно его прерывать и отправлять другой запрос. При этом поток не важно на каком шаге будет прерван ( макс. ущерба - это если на той стороне php скрипт обломается с посылкой ).

Мое решение без interrupt() такое(псевдокод):

Код
Thread::run()
{
// Здесь часть не важная к прерыванию, если ее не прерывать,а просто про нее забыть - то тоже нормально
int temp_value = 0;
Connector.open()
temp_value = Connector.get();

if (INTERRUPT_ASK_FLAG)
{
// Нас попросили уже давно выти и результаты выполнения никого не интересуют. Т.к. неврененные переменные мы не меняли, то просто выйдем.
INTERRUPT_ASK_FLAG = true;
Connector.close()
return;
}

// Здесь уже место, которое будет проходить быстро, но его ни прерывать, ни пользоваться mClassMember не следует:
NOT_INTERRUPT_FLAG=true;

mClassMember = temp_value; // в реале тут будут массивы заполняться.

NOT_INTERRUPT_FLAG=false;
}



Приложение будет действовать так:
Если пользователь нажал отмену, то

Код

while (mThread.NOT_INTERRUPT_FLAG || mThread.isAlive() )
{
Thread.getCurrent().yield();
}

mThread.INTERRUPT_ASK_FLAG = true;
// а здесь запуск нового запроса, даже если прошлый ещё не прошел.


Другое дело - что будет если телефон поддерживает макс один http запрос =(
Я ещё в инете доки почитаю, может проясниться для моего понимания как лучше сделать.

Добавлено позже (11.3.2007, 10:08):
Кстати вот должно быть неплохая книжка ( сам ещё не докачал )
J2ME Gaming Book ( размер 3.6 мб ).

Описание
Она бесплатная. (License: GNU General Public License GPL)


Разработчики: Jason Lam, Leeman Cheng, grail.
Им спасибо.

Книжка оказалась про основы и восновном про GameCanvas + Title+Sprite и т.п..
Мне не очень пригодилась, но она ещё потому что не закончена, самые интересные для меня раздеры ещё не вписаны =(
( 200 страниц книжка примерно ).


Добавлено позже (11.3.2007, 11:07):
Опять же кому интересно:

Статья PHP Interacting with J2ME
Contributed by Jason Lam

Добавлено позже (11.3.2007, 11:16):
Статья J2ME Game Optimization Secrets
by Mike Shivas -01/09/2005

Сообщение отредактировал ZaharS - 11.3.2007, 5:18
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
IceflaSh
сообщение 12.3.2007, 7:27


Интересующийся
**

Группа: Пользователи
Сообщений: 45
Регистрация: 26.6.2006
Пользователь №: 89 149
Модель телефона: e398
Прошивка: Rokr

Рейтинг: 5



Цитата(ZaharS @ 11.3.2007, 11:04) *

Другое дело - что будет если телефон поддерживает макс один http запрос =(
Я ещё в инете доки почитаю, может проясниться для моего понимания как лучше сделать.

Добавлено позже (11.3.2007, 10:08):
Кстати вот должно быть неплохая книжка ( сам ещё не докачал )
J2ME Gaming Book ( размер 3.6 мб ).

Описание
Она бесплатная. (License: GNU General Public License GPL)
Разработчики: Jason Lam, Leeman Cheng, grail.
Им спасибо.

Книжка оказалась про основы и восновном про GameCanvas + Title+Sprite и т.п..
Мне не очень пригодилась, но она ещё потому что не закончена, самые интересные для меня раздеры ещё не вписаны =(
( 200 страниц книжка примерно ).
Добавлено позже (11.3.2007, 11:07):
Опять же кому интересно:

Статья PHP Interacting with J2ME
Contributed by Jason Lam

Добавлено позже (11.3.2007, 11:16):
Статья J2ME Game Optimization Secrets
by Mike Shivas -01/09/2005


В добавок к этому(может чем то поможет или подталкнет на мысль):

J2ME Tech Tips
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 17.3.2007, 13:53


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Как местами устал от j2me =)
Недавно писал погу на си - как же приятно писать bool, на не java boolean....

Как жить без указателей и ссылок?

Я хочу чтобы работал примено такой код:

Код
HttpConnection m = null;
func( m );
m.doSome();
...
func ( HttpConnection m )
{
    m = new HttpConnection();
}



Как это сделать в передах хотя бы не красоты, а нормы?
Для того чтобы функция могла менять передаваемый int приходиться обертывать в класс Integer, на сколько это нормальное решение?

Приходиться делать всякие такие вещи:

Код
class HTTP_Connection
{
    HttpConnection con = null;
    DataInputStream dis = null;
}
...
HTTP_Connection http = new HTTP_Connection();
if ( !ConnectHTTP( url, http ) )
    return false;
...
// Открывает связь с HTTP сервером.
private boolean ConnectHTTP( String url, HTTP_Connection http )
{
    http.con = (HttpConnection)Connector.open(url);
}

Как делать правильно?
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 8.4.2007, 3:34


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Ещё жаль что в j2me нет callback функций.

А вообще с сетью вроде немплохо получилось, написал передачу двоичных данных через http и скоро выйдет Mobicraft с поддержкой чата.
Всем спасибо.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Alex-Chet
сообщение 26.4.2007, 15:55


Новичок
*

Группа: Пользователи
Сообщений: 10
Регистрация: 10.4.2006
Пользователь №: 78 093
Модель телефона: L7/9+B-S E71+SE K770
Прошивка: Svoi

Рейтинг: 0



Посаветуйте литературу по этой теме
Стоит ли качать J2ME Wireless Toolkit 2.2
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Грустный
сообщение 28.4.2007, 0:56


Dum vivimus vivamus
***

Группа: Пользователи
Сообщений: 102
Регистрация: 23.6.2006
Пользователь №: 88 814
Модель телефона: V180, V360

Рейтинг: 29



Stranger
Цитата(Stranger @ 21.11.2006, 19:11) *

Что касается сворачивания мидлета. Я не использую pauseApp()... В своей статье я не описал механизм, который я использую, однако в исходниках он есть. Посмотри в Канвасе есть два метода showNotify(), hideNotify(). При внешнем событии мидлет уйдет в паузу, но перед этим будет вызван метод hideNotify(), в котором можно грамотно поставить игру на паузу, showNotify() сработает при возвращении мидлету фокуса от внешнего события. Однако не на всех телефонах эти два метода работают. Если кому-то интересно, могу написать еще статейку о том, как можно обойти эти трудности + примеры кода...


На моторолах-раскладушках V360/V180 такой подход работает, а на SE K700 нет - милет уходит в паузу, но основное меню телефона не доступно (т.е. висит запрос "закончить"/"продолжить").
А вод подход с "переходом в фоновый режим": Display.setCurrent(null) - на SE нормально, а на V360/V180 - никакой реакции.

Так, что такая статейка была бы очень полезна.

Сообщение отредактировал Грустный - 28.4.2007, 0:59
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Stranger
сообщение 3.5.2007, 8:00


Опытный
***

Группа: Почётные мотофаны
Сообщений: 135
Регистрация: 4.7.2005
Из: Донецк,Украина
Пользователь №: 45 406

Рейтинг: 116



Хорошо, я чуть позже напишу такую статью.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Грустный
сообщение 3.5.2007, 22:50


Dum vivimus vivamus
***

Группа: Пользователи
Сообщений: 102
Регистрация: 23.6.2006
Пользователь №: 88 814
Модель телефона: V180, V360

Рейтинг: 29



В процессе изучения работы (и применения) pauseApp() и hideNotify(), наткнулся на интересную полемику на Juga.Ru:

Цитата
Maxim Kizub:
...
Вообще-то pauseApp() обычно вызывается. Хотя это может от конкретной модели телефона зависеть - некоторые операционки просто не дают процессорного времени для того, чтоб уведомить мидлет.
Часто бывает, что JVM-ка уже сделала callback мидлету (paint(), keyPressed/Released() и так далее) - мы вызвать pauseApp() не имеем права, пока коллбэк отрабатывается. А входящий звонок ждать не будет - приходится просто останавливать исполнение всей JVM-ки. Как вариант - убиваем мидлет. Всё это зависит от пожеланий заказчика и настройки операционки.
Но вызвать pauseApp() мы пытаемся... чес-слово!
...
А то половина писателей мидлетов в commandAction() меньше чем на "прочитать настройки из RMS, сделать http connection и показать в это время animated картинку" не согласны
...
Donz:
...
Кстати, вполне возможно, что если бы в документации MIDP было бы написано о том, что колбэки должны моментально возвращать управление, то довольно много разработчиков не натыкалось бы на эти грабли. Сейчас это только где-то в хинтах и советах на java.sun.com написано. Не каждая птица долетит до этих статей

...


Блин, а я, действительно, никогда не задумывался о том, что делаю в keyPressed/Released() .

Сообщение отредактировал Грустный - 3.5.2007, 22:51
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
ZaharS
сообщение 16.5.2007, 14:05


Ветеран
*****

Группа: Пользователи
Сообщений: 572
Регистрация: 13.1.2006
Пользователь №: 65 641
Модель телефона: E398
Прошивка: Based on 45R_Art3

Рейтинг: 102



Цитата(Alex-Chet @ 26.4.2007, 22:55)

Стоит ли качать J2ME Wireless Toolkit 2.2
*


Я пользуюсь WTK 2.5beta, качай самую новую конечно. качать стоит.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Elkaz
сообщение 24.5.2007, 17:08


Новичок
*

Группа: Пользователи
Сообщений: 8
Регистрация: 30.3.2007
Из: Баку
Пользователь №: 129 124
Модель телефона: E398 -> E1
Прошивка: R373_G-0E.30.79R

Рейтинг: 0



Думаю, весьма полезная тема для новичков программирования на JAVA (таких как я, к примеру smile.gif)

В данный момент 2 проблемы.
Первая
Код

/*
Starting - 23.05.07
Programmer: Elkaz
*/
// Programm name - Farida2 :-)
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.*; // import all lcdui
import javax.microedition.rms.*;
// All library are imported... start
public class Farida2 extends MIDlet{
private Display display;
private Form form;
private Command equal;
private MyCommandListener cl = new MyCommandListener();
private TextField arg1,arg2,action;
public void pauseApp() { }
public void startApp(){
form = new Form("FCalculator "+getAppProperty("MIDLET-Version"));
form.setCommandListener(cl);
equal = new Command("=",Command.OK,1);
form.addCommand(equal);
arg1 = new TextField("Число","",5,TextField.NUMERIC);
form.append(arg1);
action = new TextField("Действие","",1,TextField.ANY);
form.append(action);
arg2 = new TextField("Число","",5,TextField.NUMERIC);
form.append(arg2);
display.setCurrent(form);
}
private class MyCommandListener implements CommandListener{
public void CommandAction (Command c, Displayable d){
if (c == equal) {
Form resForm = new Form("Результат");
resForm.setCommandListener(cl);
Command back = new Command("Назад =)",Command.BACK,1);
resForm.addCommand(back);
if (arg1.size()==0 || arg2.size()==0 || action.size()==0) {
resForm.append("Ошибка: одно или несколько полей осталось не заполненными :) Заполни,"+
               "пожалуйста :))))");
display.setCurrent(resForm);
return;
}
char[] act = new char[1];
action.getChars(act);
int first = Integer.parseInt(arg1,getString());
int second = Integer.parseInt(arg2,getString());
int res = 0;
switch (act[0]) {
case '+':
    res = first+second;
    break;
case '-':
    res = first-second;
case '*':
    res = first*second;
case '/':
    res = first/second;
default:
resForm.append("Неизвестная операция :)");
display.setCurrent(resForm);
return;
}
resForm.append((new Integer(res)).toString());
display.setCurrent(resForm);
}
else { display.setCurrent(form); }
}
}
public void destroyApp(boolean unconditional){ notifyDestroyed(); }
}


Подскажите что это я конкертно делаю не так smile.gif
Следущее - можно ли в JAVA задать background в виде *png файла? smile.gif
Т.е
Код
background("somebgfile.png");


Сообщение отредактировал Elkaz - 24.5.2007, 17:09
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Alex-Chet
сообщение 27.5.2007, 14:51


Новичок
*

Группа: Пользователи
Сообщений: 10
Регистрация: 10.4.2006
Пользователь №: 78 093
Модель телефона: L7/9+B-S E71+SE K770
Прошивка: Svoi

Рейтинг: 0



ZaharS, Пасибо!
скачал WTK пока изучаю
А можно ли посмотреть, отредактировать код готовой игрушки какой-нибуть прогой .
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Игровая комната, Обмен опытом при создании игр · Разработка Java-игр · Forum
 

3 страниц V < 1 2 3 >
Ответ в темуСоздание новой темы
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 18.7.2025, 3:32

Форум живёт: