JREGC

Главная | Регистрация | Вход Приветствую Вас Инопланетяне | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Модератор форума: wawe  
Форум » PROGRAMMING CATEGORY » Уроки LWJGL » Делаем 3D игру вместе#2
Делаем 3D игру вместе#2
waweДата: Четверг, 11.10.2012, 20:17 | Сообщение # 1
Просто человек...
Группа: Администраторы
Сообщений: 50
Награды: 3
Статус: Offline
В предыдущем уроке я вам рассказывал, как сделать обычное окно. Да, как создавать обычные окна все уже знают. По этому сейчас будет идти речь о настройке GL3D метода, камеры, объектов и все.

Давайте все по порядку, начнем сперва с GL3D.

Вот, посмотрите на этот код

Code

      public void GET_INIT_GL3D() {
       GL11.glMatrixMode(GL11.GL_PROJECTION);
       GL11.glLoadIdentity();
       GLU.gluPerspective(65.0f, (float) (DISPLAY_WIDTH / DISPLAY_HEIGHT),
         0.0001f, 1050);
       GL11.glMatrixMode(GL11.GL_MODELVIEW);
       GL11.glLoadIdentity();
       GL11.glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
       GL11.glShadeModel(GL11.GL_SMOOTH);
       GL11.glClearDepth(1.0f);
       GL11.glEnable(GL11.GL_DEPTH_TEST);
       GL11.glDepthFunc(GL11.GL_LEQUAL);
       GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
       GL11.glEnable(GL11.GL_TEXTURE_2D);
      }


Эта часть кода нужна для настройки матрицы с пропорцией размеров окна.
Code

       GL11.glMatrixMode(GL11.GL_PROJECTION);
       GL11.glLoadIdentity();
       GLU.gluPerspective(65.0f, (float) (DISPLAY_WIDTH / DISPLAY_HEIGHT),
         0.0001f, 1050);
       GL11.glMatrixMode(GL11.GL_MODELVIEW);
       GL11.glLoadIdentity();


Ширина(800) делится на высоту(600) и в итоге получаем число 400. Если же записать туда другое число, окно будет неправильно себя вести, то есть, все что находится в окне.

Код
GL11.glClearColor(COLOR_RED, COLOR_GREEN, COLOR_BLUE);
служит для изменения фонового цвета окна.
В моем случае фон будет серым.

Этот код сглаживает объекты
GL11.glShadeModel(GL11.GL_SMOOTH);
Код для очистки буфера глубины
GL11.glClearDepth(1.0f);
Остальная часть кода делает просто выполняет свою работу.
GL11.glEnable(GL11.GL_TEXTURE_2D);
включает текстуры.

Если вы просто скопируете код в свою программу, он работать не будет. Потому-что мы забыли про самое главное...
Очистка экрана и буфера глубины в методе RENDER();

Вот метод
Code

      public void GET_INIT_RENDER() {
       // Очистить экран и буфер глубины
       GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
       GL11.glLoadIdentity();
      }


Метод GET_INIT_RENDER(){} служит для рендеринга всего, что будет в игре.

Если вы читали тему "LWJGL Основы - Таймер" тогда вы уже знаете, что на разных компьютерах скорость игры будет разной.
А знаете почему? Потому-что по умолчанию игра работает со скоростью FPS. Разные компьютеры с разной скоростью(от мощных до слабых) имеют разную скорость FPS. Например на слабом компьютере FPS будет - 20, а значит игра будет работать медленнее. На мощном компьютере FPS будет 90, а значить скорость игры будет настолько высокой, что человек работающий со слабым компьютером будет поражен. По скольку он не сможете уловить все объекты, которые перемещаются с большой скоростью.

Сейчас я вам покажу, как решить данную проблему.
Чтобы игра работала с одинаковой скоростью на разных компьютерах(независимо от FPS) нам понадобится еще пару сотен строк кода, шучу =)

Code

      public static float dt = 0.0f;
      public static long lastFPS;
      public static long lastFrame;
      public static int fps;

//...

      public static long GetTime() {
       return (Sys.getTime() * 1000) / Sys.getTimerResolution();
      }

      public void UpdateFPS() {
       if (GetTime() - lastFPS > 1000) {
        Display.setTitle(TITLE + " FPS: " + fps);
        fps = 0;
        lastFPS += 1000;
       }
       fps++;
      }

//...

      public void GET_INIT_RENDER() {
       // Очистить экран и буфер глубины
       GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
       GL11.glLoadIdentity();
                     UpdateFPS();
      }

//...

      public void GET_INIT_RUNNING() {
       float lastTime = 0.0f;
       float time = 0.0f;
       lastFPS = GetTime();
       // цикл будет работать до тех пор, пока RUNNING не будет равен false;
       // окно не будет закрыто; пользователь не нажмет клавишу ESC.
       while (RUNNING && !Display.isCloseRequested()
         && !keys[Keyboard.KEY_ESCAPE]) {
        time = Sys.getTime();
        dt = (time - lastTime) / 1000.0f;
        lastTime = time;
        GET_INIT_UPDATE();
        // обновление окна
        Display.update();
       }
       // asCrash == false это число 0. Выход в нормальном состоянии
       cleanUp(false);
      }


Выше вы увидели обновленный код.
Теперь проблема будет решена.

Теперь давайте создадим камеру

Camera.java
Code

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector3f;

public class Camera {

      private boolean moveForward = false;
      private boolean moveBackward = false;
      private boolean strafeLeft = false;
      private boolean strafeRight = false;
           
      private boolean onGround = false, jumping = false, falling = false;
      private final float gravity = 0.0100f;

      public float movementSpeed = 8.0f;
      public float yBottom = 0;
      public float yMotion = 0;

      public Main world;

      static Vector3f vector = new Vector3f();
      Vector3f rotation = new Vector3f();
      Vector3f previous = new Vector3f();

      public Camera(Main app) {
       world = app;
      }

      public Camera() {

      }

      public static float getX() {
       return vector.x;
      }

      public static float getY() {
       return vector.y;
      }

      public static float getZ() {
       return vector.z;
      }

      public void Update() {
       UpdatePreviousVector();
       UpdateMotion(movementSpeed * Main.dt);
       Input();
       collisions(-0.9f);
       Physics();
      }

      // позиуия камеры
      public void TranslateCamera() {
       GL11.glRotatef(rotation.x, 1.0f, 0.0f, 0.0f);
       GL11.glRotatef(rotation.y, 0.0f, 1.0f, 0.0f);
       GL11.glRotatef(rotation.z, 0.0f, 0.0f, 1.0f);
       GL11.glTranslatef(-vector.x, -vector.y - 2.4f, -vector.z);
      }

      public void UpdatePreviousVector() {
       previous.x = vector.x;
       previous.y = vector.y;
       previous.z = vector.z;
      }
           
      // физика камеры
      public void Physics() {
       onGround = (vector.y == yBottom && !jumping && !falling);
       jumping = (yMotion > 0);
       falling = (yMotion < 0);
       vector.y += yMotion;
       if (vector.y > yBottom) {
        yMotion -= gravity;
       }
       if (vector.y <= yBottom) {
        vector.y = yBottom;
        yMotion = 0;
       }
      }

      public void collisions(float offset) {
       if (!ontopOfCollidablePoly(offset)) {
        yBottom = 0;
       }
       for (Quad v : world.quad) {
        if (Math.abs(vector.x - v.centerX) < v.width / 2
          && Math.abs(vector.z - v.centerZ) < v.length / 2) {
         if ((Math.abs(vector.y - v.yTop * 2) < v.height + (offset))
           || vector.y > v.yBottom + v.height - 0.5f) {
          yBottom = v.y1 + v.yTop;
         } else if (v.yBottom > vector.y + 2.4f) {

         } else {
          vector.x = previous.x;
          vector.z = previous.z;
         }
        }
       }
      }

      private boolean ontopOfCollidablePoly(float offset) {
       for (Quad v : world.quad) {
        if (Math.abs(vector.x - v.centerX) < v.width / 2
          && Math.abs(vector.z - v.centerZ) < v.length / 2) {
         return true;
        }
       }
       return false;
      }
           
      // управление
      public void Input() {
       if (Main.keys[Keyboard.KEY_W]) {
        moveForward = true;
       } else {
        moveForward = false;
       }
       if (Main.keys[Keyboard.KEY_S]) {
        moveBackward = true;
       } else {
        moveBackward = false;
       }
       if (Main.keys[Keyboard.KEY_A]) {
        strafeLeft = true;
       } else {
        strafeLeft = false;
       }
       if (Main.keys[Keyboard.KEY_D]) {
        strafeRight = true;
       } else {
        strafeRight = false;
       }
       if (Main.keys[Keyboard.KEY_SPACE] && onGround) {
        yMotion = 0.2f;
       }
       // если курсор исчез...
       if (Mouse.isGrabbed()) {
        // произойдет FIX камеры
        float mouseDX = Mouse.getDX() * 0.8f * 0.16f;
        float mouseDY = Mouse.getDY() * 0.8f * 0.16f;
        if (rotation.y + mouseDX >= 360) {
         rotation.y = rotation.y + mouseDX - 360;
        } else if (rotation.y + mouseDX < 0) {
         rotation.y = 360 - rotation.y + mouseDX;
        } else {
         rotation.y += mouseDX;
        }
        if (rotation.x - mouseDY >= -89 && rotation.x - mouseDY <= 89) {
         rotation.x += -mouseDY;
        } else if (rotation.x - mouseDY < -89) {
         rotation.x = -89;
        } else if (rotation.x - mouseDY > 89) {
         rotation.x = 89;
        }
       }
      }

      public void UpdateMotion(float distance) {
       if (moveForward) {
        vector.x += distance * (float) Math.sin(rotation.y * Math.PI / 180);
        vector.z += -distance
          * (float) Math.cos(rotation.y * Math.PI / 180);
       }
       if (moveBackward) {
        vector.x -= distance * (float) Math.sin(rotation.y * Math.PI / 180);
        vector.z -= -distance
          * (float) Math.cos(rotation.y * Math.PI / 180);
       }
       if (strafeLeft) {
        vector.x += distance
          * (float) Math.sin((rotation.y - 90) * Math.PI / 180);
        vector.z += -distance
          * (float) Math.cos((rotation.y - 90) * Math.PI / 180);
       }
       if (strafeRight) {
        vector.x += distance
          * (float) Math.sin((rotation.y + 90) * Math.PI / 180);
        vector.z += -distance
          * (float) Math.cos((rotation.y + 90) * Math.PI / 180);
       }
      }
}

Скопируйте код себе.
и еще код куба
Code

import org.lwjgl.opengl.GL11;

public class Quad {

      float x1, y1, z1, x2, y2, z2, centerX, centerY, centerZ;
      float width, height, length;
      float yTop2;
      float yTop, yBottom;
      int num;
      float cX2, cY2, cZ2;

      public Quad(float startX, float startY, float startZ, float endX,
        float endY, float endZ, int number, float gh, float hj, float yu) {
       x1 = startX;
       y1 = startY;
       z1 = startZ;
       x2 = endX;
       y2 = endY;
       z2 = endZ;
       width = x2 - x1;
       height = y2 - y1;
       length = z2 - z1;
       centerX = x1 + (width / 2);
       centerY = y2 + (height / 2);
       centerZ = z1 + (length / 2);
       yTop = Math.abs(y2 - y1);
       yBottom = y1 + yTop - height;
       num = number;
       cX2 = gh;
       cY2 = hj;
       cZ2 = yu;
      }

      // рендер блока
      public void render() {
       GL11.glPushMatrix();
       GL11.glColor3f(cX2, cY2, cZ2);
       GL11.glBegin(GL11.GL_QUADS);
       // Top
       GL11.glVertex3f(x1, y1, z1);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1 + width, y1, z1);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1 + width, y1, z1 + length);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1, y1, z1 + length);
       GL11.glTexCoord2f(0, 0.9f);
       // Bottom
       GL11.glVertex3f(x1, y1 + height, z1);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1 + width, y1 + height, z1);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1 + width, y1 + height, z1 + length);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1, y1 + height, z1 + length);
       GL11.glTexCoord2f(0, 0.9f);
       // Front
       GL11.glVertex3f(x1, y1, z1);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1 + width, y1, z1);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1 + width, y1 + height, z1);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1, y1 + height, z1);
       GL11.glTexCoord2f(0, 0.9f);
       // Back
       GL11.glVertex3f(x1, y1, z1 + length);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1 + width, y1, z1 + length);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1 + width, y1 + height, z1 + length);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1, y1 + height, z1 + length);
       GL11.glTexCoord2f(0, 0.9f);
       // Left side
       GL11.glVertex3f(x1, y1, z1);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1, y1, z1 + length);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1, y1 + height, z1 + length);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1, y1 + height, z1);
       GL11.glTexCoord2f(0, 0.9f);
       // Right side
       GL11.glVertex3f(x1 + width, y1, z1);
       GL11.glTexCoord2f(0, 0);
       GL11.glVertex3f(x1 + width, y1, z1 + length);
       GL11.glTexCoord2f(0.9f, 0);
       GL11.glVertex3f(x1 + width, y1 + height, z1 + length);
       GL11.glTexCoord2f(0.9f, 0.9f);
       GL11.glVertex3f(x1 + width, y1 + height, z1);
       GL11.glTexCoord2f(0, 0.9f);
       GL11.glEnd();
       GL11.glPopMatrix();
      }
}


обновленный код главного класса
Main.java
Code

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

public class Main {

      public static boolean[] keys = new boolean[256];
      public static final int DISPLAY_WIDTH = 800;
      public static final int DISPLAY_HEIGHT = 600;
      public String TITLE = "GL3Dgame";
      public boolean VSYNC_ENABLED = false;
      public boolean RUNNING = true;
      public static final int MAX_FPS = 100;
      public static float dt = 0.0f;
      public static long lastFPS;
      public static long lastFrame;
      public static int fps;

      // создание камеры
      Camera camera = new Camera(this);

      // блоки
      List<Quad> quad = new ArrayList<Quad>();

      // конструктор главного класса Main.
      public Main() {
       // добавить один блок
       // quad.add(new Quad(startX, startY, startZ, endX, endY, endZ, textureNum, colorX, colorY, colorZ));
       // что значит textureNum, вы узнаете в следующем уроке.
       quad.add(new Quad(4, 0.1f, 4, 6, 2.1f, 6, 1, 1, 1, 1));
      }

      public static long GetTime() {
       return (Sys.getTime() * 1000) / Sys.getTimerResolution();
      }

      public void UpdateFPS() {
       if (GetTime() - lastFPS > 1000) {
        Display.setTitle(TITLE + " FPS: " + fps);
        fps = 0;
        lastFPS += 1000;
       }
       fps++;
      }

      // заготовка для настройки дисплея.
      public void GET_INIT_DISPLAY() {
       try {
        // настраиваем размеры окна, в моем случае это 800x600
        Display.setDisplayMode(new DisplayMode(DISPLAY_WIDTH,
          DISPLAY_HEIGHT));
        // меняем заголовок окна
        Display.setTitle(TITLE);
        // вертикальная синхронизация в этот момент отключена
        Display.setVSyncEnabled(VSYNC_ENABLED);
        // создаем окно
        Display.create();
        // если появилась ошибка...
       } catch (LWJGLException e) {
        // выводим в консоль сообщение об ошибке
        System.err.println("Error: Display.create");
        // здесь объяснять не буду.
        e.printStackTrace();
        // asCrash == true это число 1, сообщаем всем, что причина очистки
        // из за ошибки
        cleanUp(true);
       }

       // это настройка Opengl
       GET_INIT_GL3D();
       // запускаем цикл
       GET_INIT_RUNNING();
      }

      // заготовка для настройки 3D OpenGL.
      public void GET_INIT_GL3D() {
       GL11.glMatrixMode(GL11.GL_PROJECTION);
       GL11.glLoadIdentity();
       GLU.gluPerspective(65.0f, (float) (DISPLAY_WIDTH / DISPLAY_HEIGHT),
         0.0001f, 1050);
       GL11.glMatrixMode(GL11.GL_MODELVIEW);
       GL11.glLoadIdentity();
       GL11.glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
       GL11.glShadeModel(GL11.GL_SMOOTH);
       GL11.glClearDepth(1.0f);
       GL11.glEnable(GL11.GL_DEPTH_TEST);
       GL11.glDepthFunc(GL11.GL_LEQUAL);
       GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
       GL11.glEnable(GL11.GL_TEXTURE_2D);
      }

      public void GET_INIT_RENDER() {
       // Очистить экран и буфер глубины
       GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
       GL11.glLoadIdentity();
       // установка позиции камеры
       camera.TranslateCamera();
       // рендеринг всех блоков
       for (Quad q : quad) {
        q.render();
       }
      }

      // здесь мы поместим все в один метод, чтобы было легче работать.
      public void GET_INIT_UPDATE() {
       // установка камеры
       camera.Update();
       // скрытие курсора
       Mouse.setGrabbed(true);
       mapKeys();
       GET_INIT_RENDER();
       UpdateFPS();
      }

      // ну а здесь будет главный цикл игры.
      public void GET_INIT_RUNNING() {
       float lastTime = 0.0f;
       float time = 0.0f;
       lastFPS = GetTime();
       // цикл будет работать до тех пор, пока RUNNING не будет равен false;
       // окно не будет закрыто; пользователь не нажмет клавишу ESC.
       while (RUNNING && !Display.isCloseRequested()
         && !keys[Keyboard.KEY_ESCAPE]) {
        time = Sys.getTime();
        dt = (time - lastTime) / 1000.0f;
        lastTime = time;
        GET_INIT_UPDATE();
        // обновление окна
        Display.update();
        Display.sync(MAX_FPS);
       }
       // asCrash == false это число 0. Выход в нормальном состоянии
       cleanUp(false);
      }

      // массив для хранения Keyboard
      public void mapKeys() {
       for (int i = 0; i < keys.length; i++) {
        keys[i] = Keyboard.isKeyDown(i);
       }
      }

      // очистка и разрушение окна
      public void cleanUp(boolean asCrash) {
       Display.destroy();
       System.exit(asCrash ? 1 : 0);
      }

      // здесь и так все понятно.
      public static void main(String[] args) {
       Main main = new Main();
       main.GET_INIT_DISPLAY();
      }
}


Как вы уже заметили, в классе Camera есть метод collision() все мечтали о том, чтобы камера не проходила сквозь объекты =)
Только проблема, что этот код не работает полностью.
В следующем уроке я покажу вам как нанести на куб текстуру


Сообщение отредактировал wawe - Пятница, 12.10.2012, 17:11
 
waweДата: Понедельник, 12.11.2012, 19:28 | Сообщение # 2
Просто человек...
Группа: Администраторы
Сообщений: 50
Награды: 3
Статус: Offline
Вот обновленная коллизия камеры
Code

     public void collisions(float offset) {
  if (clip) {
      if (!ontopOfCollidablePoly(offset)) {
   yBottom = 0;
      }
      for (Quad v : world.map.quad) {
   if (Math.abs(vector.x - v.centerX) < (v.width / 2) + 0.2f
    && Math.abs(vector.z - v.centerZ) < (v.length / 2) + 0.2f) {
       if ((Math.abs(vector.y - v.y2) < v.height + (offset))
        || vector.y > v.yBottom + v.height - 0.5f) {
    if (vector.y > v.y2 - 0.01f) {
        yBottom = v.y1 + v.yTop;
    } else {
        if (Math.abs(vector.x - v.centerX) < (v.width / 2) + 0.2f) {
     vector.x = previous.x;
        }
        if (Math.abs(vector.z - v.centerZ) < (v.length / 2) + 0.2f) {
     vector.z = previous.z;
        }
    }
       } else if (v.yBottom > vector.y + 2.4f) {
    if (vector.y + 3 > v.y1) {
        yMotion = 0;
        vector.y = v.y1 - 3;
    }
       } else {
    vector.x = previous.x;
    vector.y = previous.y;
    vector.z = previous.z;
       }
   }
      }
  }
     }
 
kodoДата: Понедельник, 03.06.2013, 23:40 | Сообщение # 3
Рядовой
Группа: Пользователи
Сообщений: 7
Награды: 0
Репутация: 0
Статус: Offline
Не прошло и пол года и я вернулся к своему проектику) И нашёл "баг" вот в этой строчке:
GLU.gluPerspective(65.0f, (float) (DISPLAY_WIDTH / DISPLAY_HEIGHT), 0.0001f, 1050);
Собственно ошибка в (float) (DISPLAY_WIDTH / DISPLAY_HEIGHT)  - преобразование к флоту идёт после вычисления соотношения, а само соотношение считается для целочисленных, и получается целым, а потом преобразуется к дробному. Собственно сам баг хорошо видно если запрыгнуть на кубик и повертеть камерой, видно как не пропорционально он меняется, да ине кубик он при этом, а прямоугольник.
Решить можно например записав так:
GLU.gluPerspective(65.0f, (float)DISPLAY_WIDTH / DISPLAY_HEIGHT, 0.0001f, 1050);
собственно перед делением одна из величин становится дробной и результатом деления уже будет дробное, а не целое.
 
Форум » PROGRAMMING CATEGORY » Уроки LWJGL » Делаем 3D игру вместе#2
  • Страница 1 из 1
  • 1
Поиск:

Copyright MyCorp © 2024
Используются технологии uCoz