Uncategorized

Lwjgl 3D Game Engine

Welcome to the second part .Today we are going make our window and an interface class that will make our engine reusable to make different type of games . Any class that will implement the interface will inherit all its methods . 

package gameLoop;

public interface Game{

void audio();

void dispose();

void render();

void update(float time);

void input();

void init()throws Exception;

}

OK now  we can create our window . So create a new class called Display.

Public class Display{

public static final into width = 800;

public static final int  height = 600;

private static long lastFrameTime ;

private static float delta;

private static int last frame;

private static int fps;

private static long lastFps;

public static boolean vsync;

We define some properties for our window ,the width and height . The other variables will help us calculate our fps at run time . Vsync  prevents screen tearing  but  we define it as a boolean because  we want to be able to change it at runtime .

public static void createDisplay(){

ContextAttribs attribs = new ContextAttribs(3,2).withForwardCompatible(true).withProfileCore(true);

try{

Display. setDisplayMode(new Display Mode(WIDTH,HEIGHT));

Display. create(new PixelFormat().withDepthBits(24),attribs);

Display. setTitle(“Game Engine”);

Display. setInitialBackground(1,1,1);

GL11.glEnable (GL13.GL_MULTISAMPLE);

}catch(LWJGLException e){

e.printStackTrace();

System.err.printing(“Couldn’t create display”);

System. exit(-1);

}

GL11.glViewport(0,0,WIDTH, HEIGHT);

lastFrameTime = getCurrentTime();

getDelta();

lastFps  = get time();

}

We create our display in this method and set its parameters . When you create the context you need to input the opengl version  supported by your GPU .In my case its 3,2 . 

public static float getCurrentTime(){

return Sys.get time()*1000/Sys.getTimerResolution();

}

public static void update display(){

Display. sync(GameEngine.TARGET_FPS);

Display.update ();

long current FrameTime = getCurrentTime();

delta = (current FrameTime – lastFrameTime)/1000f;

lastFrameTime = current FrameTime;

updateFps();

update(delta);

}

public static float getFrameTimeSeconds(){

return delta;}

public static void destroyDisplay(){

Display. destroy;}

public static void update (float delta){

while(Keyboard.next()){

if(keyboard.getEventKeyState()){ if(keyboard. getEventKey()==keyboard. KEY_F){

setDisplayMode(WIDTH, HEIGHT,! Display. isFullscreen());}

if(keyboard.get eventKey()==keyboard. KEY_V){

vsync =!vsync;

Display. setVSyncEnable(vsync);

}}}}

we sync the display to update at our target frame rate  . We also make it possible for us to change both the screen settings (between full screen and window mode) and vsync. The rest of the code is self explanatory . The finished Display class.



public static final int WIDTH = 800;

 public static final int HEIGHT = 600;

 

 private static long lastFrameTime;

 private static float delta;

 

    private static int lastFrame;

 

 private static int fps;

 

 private static long lastFps;

 

 public static boolean vsync;

 


 public static void createDisplay(){

  ContextAttribs attribs = new ContextAttribs(1,3)

  .withForwardCompatible(true);

 

  try {

   

   Display.setDisplayMode(new DisplayMode(WIDTH,HEIGHT));

   Display.create(new PixelFormat().withDepthBits(24), attribs);

   Display.setTitle(“Game enginet”);

   Display.setInitialBackground(1, 1, 1);

   GL11.glEnable(GL13.GL_MULTISAMPLE);

   

  } catch (LWJGLException e) {

   e.printStackTrace();

   System.err.println(“Couldn’t create display!”);

   System.exit(-1);

  }

 

 

  GL11.glViewport(0,0,WIDTH,HEIGHT);

  lastFrameTime = getCurrentTime();

  getDelta();

  lastFps = getTime();

 }

 private static long getCurrentTime() {

  return Sys.getTime()*1000/Sys.getTimerResolution();

 }

 public static void updateDisplay(){

  Display.sync(GameEngine.TARGET_FPS);

  Display.update();

 

  long currentFrameTime = getCurrentTime();

  delta = (currentFrameTime – lastFrameTime)/1000f;

  lastFrameTime = currentFrameTime;

  updateFps();

  update(delta);

 }

 public static float getFrameTimeSeconds(){

  return delta;

 }

 public static void destroyDisplay(){

   Display.destroy();

 

 }

   public static void update(float delta){

 

  while(Keyboard.next()){

   if(Keyboard.getEventKeyState()){

    if(Keyboard.getEventKey()==Keyboard.KEY_F){

     setDisplayMode(WIDTH,HEIGHT,!Display.isFullscreen());

    }

    if(Keyboard.getEventKey() == Keyboard.KEY_V){

     

      vsync =!vsync;

      Display.setVSyncEnabled(vsync);

     

    }

   }

  }

 

 }

   

   public static void setDisplayMode(int width,int height,boolean fullscreen){

 

  if((Display.getDisplayMode().getWidth() == width)&&

    (Display.getDisplayMode().getHeight() == height)&&

    (Display.isFullscreen() == fullscreen)){

   return;

  }

 

  try{

   DisplayMode targetDisplayMode = null;

   

   if(fullscreen){

    DisplayMode[] modes = Display.getAvailableDisplayModes();

    int freq = 0;

   

    for(int i = 0;i<modes.length;i++){

     DisplayMode current = modes[i];

     

     if((current.getWidth() == width)&&(current.getHeight()==height)){

     

      if((targetDisplayMode ==null)||(current.getFrequency()>=freq)){

       

       if((targetDisplayMode ==null)||(current.getBitsPerPixel()>targetDisplayMode.getBitsPerPixel()))

       {

        targetDisplayMode = current;

        freq = targetDisplayMode.getFrequency();

       }

      }

      if((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel())&&

       

        (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())){

       targetDisplayMode = current;

       

       break;

      }

     }

    }

   }else{

    targetDisplayMode = new DisplayMode(width,height);

   }

   if(targetDisplayMode == null){

    System.out.println(“Failed to find value mode”+width+”x”+height+”fs=”+fullscreen);

    return;

   }

   Display.setDisplayMode(targetDisplayMode);

   Display.setFullscreen(fullscreen);

  }catch(LWJGLException e){

   System.out.println(“Unable to setup mode”+width+”x”+height+”fullscreen=”+fullscreen + e);

  }

 }

 public static int getDelta(){

  long time = getTime();

  int delta =(int)(time – lastFrame);

  lastFrame = (int) time;

 

  return delta;

 }

 public static long getTime(){

  return Sys.getTime() * 1000/ Sys.getTimerResolution();

 }

 

 public static void updateFps(){

  if(getTime() – lastFps > 1000){

   Display.setTitle(“FPS:”+ fps);

   fps = 0;

   lastFps += 1000;

  }

  fps++;

 }

Well that’s it for now .Feel free to leave a comment cheers!.



Advertisements
Uncategorized

Lwjgl 3D Game Engine.

For some months now I have been learning opengl so that I can make my own 3D video games . So I decided to make my own game engine that I will use in making my games.
Note: The code used in this tutorial is far  from perfect also note that I assume you know basic java and eclipse (the IDE I’m using) . With that out of the way let’s  get started. 

 Create a new  project in eclipse call it whatever you like .  You can download the lwjgl library here Download the lwjgl 2  version  don’t go for lwjgl 3 since they are very different and I’m using lwjgl 2.xx so if you choose to get lwjgl 3 you are on your own.
Setting up lwjgl in eclipse .

  • Right click on your project folder and go to properties.
  • Right click on java Build Path and select the libraries tab.
  • To add lwjgl to your project click on either Add JARs…. or Add External JARs…. depending on where your lwjgl folder is on your computer .
  • Once in your lwjgl folder select lwjgl_utils ,lwjgl . 
  • Then click on lwjgl.jar and select native  library and navigate to the lwjgl files and select natives and choose your operating system .

        Now that the lwjgl is added to our project we can start making our game engine . 
        The Game Loop .

        I am going to be using a fixed step game loop for the game engine over the  variable step game loop .Each type of loop has its own pros and cons ,if you have time I recommend that you do your own research and decide which game loop is good for you . 

        Create a new package called gameLoop and create a GameEngine class. 

        package gameLoop;

        public class GameEngine implements Runnable {

        public static final int TARGET_FPS = 120;

        public static final int TARGET_EPS=30;

        private final Timekeeper keeper;

        private final Thread gameThread;

        public GameEngine(){

        gameThread = new Thread(this,””);

        keeper = new TimeKeeper();

        public void thread(){

        String osName = System.getProperty(“os.name”);

        If(osName.contains(“Mac”)){

        gameThread.run();

        }else{

        gameThread.start();}

        }

        @Override

        public void run(){

        try{

        create();

        gameLoop();

        }catch(Exception e ){

        e.printStackTrace();

        }}

        protected void gameloop(){

        float elapsedTime;

        float accumulator = 0f;

        float intervals = 1f/ TARGET_EPS ;

        boolean isRunning = true;

        while(isRunning && !Display.isCloseRequested()){

        elapsedTime = keeper.getElapsedTime();

        while(accumulator >= intervals){

        update(intervals);

        accumulator -= intervals;

        }

        float loop = 1f / TARGET_FPS;

        double time = keeper.getLastLoopTime() + loop ;

        while(keeper.getTime() < time){

        try{

        Thread.sleep(1);}catch(InterruptedException e){

        }

        }}

        Our gameEngine class implements Runnable so that we can have access to use the Thread (create a new Thread when run() is called) . Once you implement Runnable you will notice that you have to implement its method  run the next lines are self explanatory . In the thread method we check which operating system the engine is running .If we tried to run the engine while calling gameThread.start() on a mac an exception will occur , thats why we have to check which operating system our engine is being run on  . The rest of the code is the fixed time step we implement in our game engine.  

        Now we need to create our TimeKeeper class that  calculates the time difference since we last updated  .  

        package gameLoop;

        public class Timer {

        private double lastTick;

        public void init(){

        lastTick = getTime():

        }

        public double getTime(){

        return System.nanoTime()/1000000000.0;

        }

        public float  getElapsedTime(){

        double tick = getTime();

        float elapsedTime =(float)(tick-lastTick);

        lastTick = tick;

        return elapsedTime;

        }

        public double getLastTickTime(){return last Tick}}

          So thats our game loop done for now . next time we are going to make our display(just a black screen) using opengl . Feel free to comment cheers!