I'm working on creating a 2D Java game with a lighting engine with OpenGL using LWJGL, but I've hit a wall when trying to link up keyboard inputs.
The render loop works fine, but as soon as I tried to implement a JFrame/canvas and the getParent/KeyListener combo The application crashes immediately after starting up.
I have to shut the application down in netbeans - the window doesn't respond to right clicking application's entry in the start toolbar.
public static void main(String[] args) {
Main main = new Main();
main.run();
}
public void run() {
initialize();
//animLoop();
}
private void initialize() {
try {
Frame theFrame = new Frame("Inlight");
Canvas theCanvas = new Canvas();
theCanvas.setMinimumSize(new Dimension(windowWidth, windowHeight));
theFrame.setSize(windowWidth, windowHeight);
theCanvas.requestFocusInWindow();
theFrame.add(theCanvas);
theFrame.setVisible(true);
//before doing the following, I need to create the canvas within which openGL does it's rendering
//create it before applying keylistener
Display.setDisplayMode(new DisplayMode(windowWidth, windowHeight));
Display.setParent(theCanvas);
Display.getParent().addKeyListener(new InlightKeyListener());
Display.create(new PixelFormat(0, 16, 1));
} catch (Exception e) {
e.printStackTrace();
}
shaderProgram = glCreateProgram();
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
StringBuilder fragmentShaderSource = new StringBuilder();
try {
String line;
BufferedReader reader = new BufferedReader(new FileReader("src/shader.frag"));
//points to the shader doc
while ((line = reader.readLine()) != null) {
fragmentShaderSource.append(line).append("\n");
}
} catch (IOException e) {}
glShaderSource(fragmentShader, fragmentShaderSource);
glCompileShader(fragmentShader);
if (glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
System.err.println("Fragment shader not compiled!");
}
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glValidateProgram(shaderProgram);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, 1, -1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_STENCIL_TEST);
glClearColor(0, 0, 0, 0);
System.out.println("Done initialize");
}
public synchronized void animLoop() {
//This method will loop the render
long startTime = System.currentTimeMillis();
//sets the starting time to the current time
long curTime = startTime;
//The current time measurement, so at thestart the curTime = starting time
while (curTime - startTime < 1800) {
long timePassed = System.currentTimeMillis() - curTime;
//Makes the timePassed variable equal to the System's current time - the last measured current time.
curTime += timePassed;
//updates the measurement of the current time to the actual current time. (I imagine some small amount to time is lost while it is updated. this is negligible.)
organiseTitle();
//sets up the ojects to display the title screen for 1800 milliseconds
render();
//draws the new screen scene to the display
clearObj();
//cleans up the items built for that last render
}
while (!Display.isCloseRequested()) {
long timePassed = System.currentTimeMillis() - curTime;
//Makes the timePassed variable equal to the System's current time - the last measured current time.
curTime += timePassed;
//updates the measurement of the current time to the actual current time. (I imagine some small amount to time is lost while it is updated. this is negligible.)
Organiselevel1(20, 200);
render();
//draws the new screen scene to the display
clearObj();
//cleans up the items built for that last render
}
glDeleteShader(fragmentShader);
glDeleteProgram(shaderProgram);
Display.destroy();
//closes the window
}
//There's more code after this point of course, but it's all already been tested and works.
Oh god I only just realized the call to my main loop was commented out.
/facepalm
Related
I am an in-school amateur making a snake game in java, it is not complete and i have run into a problem that i cant seem to fix. the first and second parts of the body show up just fine after eating the target, but after that they do not.
code that adds a body part:
public void addBody(int x, int y) {
snekBody.add(new JPanel());
snekBody.get(snekBody.size() - 1).setBackground(new Color(new Random().nextInt(255), new Random().nextInt(255), new Random().nextInt(255)));
snekBody.get(snekBody.size() - 1).setVisible(true);
snekBody.get(snekBody.size() - 1).setBounds(x*score, y*score, BODY_WIDTH, BODY_HEIGHT);
game.add(snekBody.get(this.snekBody.size() - 1));
revalidate();
}
}
code that moves the body parts(moveUp, moveDown, etc.:
public synchronized void moveRight(int x, int y) {
timer++;
while (!this.right) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
head.setBounds(x, y, 20, 20);
xCoords.add(x);
yCoords.add(y);
//snekBody is an ArrayList of type JPanel
for(int i = 0; i < snekBody.size(); i++) {
if (i > 0) {
snekBody.get(i).setBounds(xCoords.get(timer-(10*score)), yCoords.get(timer-(10*score))+5, BODY_WIDTH, BODY_HEIGHT);
} else {
snekBody.get(i).setBounds(xCoords.get(timer-10), yCoords.get(timer-10)+5, BODY_WIDTH, BODY_HEIGHT);
}
}
repaint();
notifyAll();
revalidate();
}
code that calls addBody:
if (snek.up) {
snek.addBody(snek.xCoords.get(snek.timer-20), snek.yCoords.get(snek.timer-20));
the second picture is the snake when more than two targets have been eaten. the panels for the body just stop showing up.
The first picture is the snake when two targets have been eaten
Turns out that the panels were showing up on top of each other, thus why i could not see them.
I'm working on a grapher that gets an expression like x^2 + t from the user and then will ask the user for range of x and t .
t in here is the timer variable.
so in x^2 + t the user for example will choose the -10 to 10 for x and 1 to 5 for t . now by clicking the draw button in GUI program the code will start plotting the expression from minimum t (1 in here) and after each second(or any time period) will increase the t value by one and draw the expression with new t (2 ,3 until it reaches the maximum range).
how can make the event handler to do this? I have found a way to draw multiple graphs but I can't make a delay so the minimum to maximum .
I know I should use timer but I don't know how to use in this part of the code
the Link for the whole code
this is the part of code in plotter class that should be changed :
// Grapher
drawButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
String testSpring = null;
String tVarString = null;
for (int i = 0; i < 5; i++) {
testSpring = inputExpression;
tVarString = String.valueOf(i);
testSpring = testSpring.replaceAll("t", tVarString);
Equation equation = new Equation(testSpring);
graph.addEquation(equation);
}
}
catch (EquationSyntaxException e) {
e.printStackTrace();
}
}
});
This is the picture of the program :
my priority is to make the program run just by clicking draw button
but It would be better if this timer could be influence JSlider
so the min and max of t would be min and max of Jslider and by clicking draw it would start drawing by every time slider knob would point at a value for t
Take a look at How to use Swing Timers
This will allow you to setup a callback at a regular interval, which is executed from within the context of the EDT, making it safe to update the UI from within
public void actionPerformed(ActionEvent arg0) {
Timer timer = new Timer(1000, new ActionListener() {
private int iteration;
#Override
public void adtionPerformed(ActionEvent evt) {
try {
String testSpring = null;
String tVarString = null;
testSpring = inputExpression;
tVarString = String.valueOf(iteration);
testSpring = testSpring.replaceAll("t", tVarString);
Equation equation = new Equation(testSpring);
graph.addEquation(equation);
} catch (EquationSyntaxException e) {
e.printStackTrace();
} finally {
iteration++
if (iteration > 4) {
((Timer)evt.getSource()).stop();
}
}
}
});
timer.start();
}
});
Okay, so why would my frames per second drop at a random time while playing the game? and what can I do to fix it. Below im going to show the code that I have with the engine that was built.
public Engine() {
Log.d("Engine","Engine constructor");
p_view = null;
p_canvas = null;
p_thread = null;
p_running = false;
p_paused = false;
p_resume = false;
p_paintDraw = null;
p_paintFont = null;
p_numPoints = 0;
p_typeface = null;
p_preferredFrameRate = 40;
p_sleepTime = 1000 / p_preferredFrameRate;
p_pauseCount = 0;
p_group = new LinkedList<Sprite>();
}
/**
* Runnable.run thread method (MAIN LOOP)
*/
#Override
public void run() {
Log.d("Engine","Engine.run start");
ListIterator<Sprite> iter=null, iterA=null, iterB=null;
Timer frameTimer = new Timer();
int frameCount=0;
int frameRate=0;
long startTime=0;
long timeDiff=0;
while (p_running) {
// Process frame only if not paused
if (p_paused) continue;
// Calculate frame rate
frameCount++;
startTime = frameTimer.getElapsed();
if (frameTimer.stopwatch(1000)) {
frameRate = frameCount;
frameCount = 0;
//reset touch input count
p_numPoints = 0;
}
// Call abstract update method in sub-class
update();
/**
* Test for collisions in the sprite group.
* Note that this takes place outside of rendering.
*/
iterA = p_group.listIterator();
while (iterA.hasNext()) {
Sprite sprA = (Sprite)iterA.next();
if (!sprA.getAlive()) continue;
if (!sprA.getCollidable()) continue;
/*
* Improvement to prevent double collision testing
*/
if (sprA.getCollided())
continue; //skip to next iterator
//iterate the list again
iterB = p_group.listIterator();
while (iterB.hasNext()) {
Sprite sprB = (Sprite)iterB.next();
if (!sprB.getAlive()) continue;
if (!sprB.getCollidable()) continue;
/*
* Improvement to prevent double collision testing
*/
if (sprB.getCollided())
continue; //skip to next iterator
//do not collide with itself
if (sprA == sprB) continue;
/*
* Ignore sprites with the same ID? This is an important
* consideration. Decide if your game requires it or not.
*/
if (sprA.getIdentifier() == sprB.getIdentifier())
continue;
if (collisionCheck(sprA, sprB)) {
sprA.setCollided(true);
sprA.setOffender(sprB);
sprB.setCollided(true);
sprB.setOffender(sprA);
break; //exit while
}
}
}
// begin drawing
if (beginDrawing()) {
// Call abstract draw method in sub-class
draw();
/**
* Draw the group entities with transforms
*/
iter = p_group.listIterator();
while (iter.hasNext()) {
Sprite spr = (Sprite)iter.next();
if (spr.getAlive()) {
spr.animate();
spr.draw();
}
}
/**
* Print some engine debug info.
*/
int x = p_canvas.getWidth()-150;
p_canvas.drawText("ENGINE", x, 20, p_paintFont);
p_canvas.drawText(toString(frameRate) + " FPS", x, 40,
p_paintFont);
p_canvas.drawText("Pauses: " + toString(p_pauseCount),
x, 60, p_paintFont);
// done drawing
endDrawing();
}
/*
* Do some cleanup: collision notification, removing
* 'dead' sprites from the list.
*/
iter = p_group.listIterator();
Sprite spr = null;
while (iter.hasNext()) {
spr = (Sprite)iter.next();
//remove from list if flagged
if (!spr.getAlive()) {
iter.remove();
continue;
}
//is collision enabled for this sprite?
if (spr.getCollidable()) {
//has this sprite collided with anything?
if (spr.getCollided()) {
//is the target a valid object?
if (spr.getOffender() != null) {
/*
* External func call: notify game of collision
* (with validated offender)
*/
collision(spr);
//reset offender
spr.setOffender(null);
}
//reset collided state
spr.setCollided(false);
}
}
}
// Calculate frame update time and sleep if necessary
timeDiff = frameTimer.getElapsed() - startTime;
long updatePeriod = p_sleepTime - timeDiff;
if (updatePeriod > 0) {
try {
Thread.sleep( updatePeriod ); // i notice this is called when frames are low
}
catch(InterruptedException e) {}
}
}//while
Log.d("Engine","Engine.run end");
System.exit(RESULT_OK);
}
public void setFrameRate(int rate) {
p_preferredFrameRate = rate;
p_sleepTime = 1000 / p_preferredFrameRate;
}
So this is not the entire engine, but it is everything that deals with the frames Why is it randomly dropping? What I am noticing that thread.sleep is being called when the frames drop below 15. I am using a nexus 5 to test this running on android 4.4.2, and My question here is How do I stop the frames from dropping that low and having it sleep especially after calling a recreate(); method when you lose the game?
Just take out the Thread.Sleep statement altogether. Or just pass "0" into the Sleep call (if you are trying to yield cycles to other threads and processes). On each cycle of the run() loop, calculate how much time actually elapsed and update your simulation based on this value. In other words, don't try to force a hard-coded frame rate.
The device has an upperbound on frame rate (60fps on my device). So you'll likely be sleeping a little during each loop anyway.
I've coded a complex Snake game using Swing components.
I have a timer (call it moveRate) that calls repaint(); every x ms (x is changed during game and never goes below 50).
Now for the issue: I'm successful playing like 4 min or so before the whole frame freezes.
MoveRate class:
class MoveRate extends Timer{
private Date dateCreated=new Date();
private long timeLast=0;
public MoveRate(){
super(190, null);
dateCreated=new Date();
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(getWidth()>0 && getHeight()>0){
if(points.get(0).x+HOPS>getWidth() || points.get(0).x<0 ||
points.get(0).y+HOPS>getHeight() || points.get(0).y<0)
if(!crosswalls && !cheats){
moveRate.stop();
prizeRate.stop();
GameOver();
}
else{
if(points.get(0).y<0)
points.get(0).y=sp.getHeight()-HOPS;
else if(points.get(0).y+HOPS>sp.getHeight())
points.get(0).y=0;
else if(points.get(0).x<0)
points.get(0).x=sp.getWidth()-HOPS;
else
points.get(0).x=0;
}
timeLast=(System.currentTimeMillis()-dateCreated.getTime())/SECONDS;
score+=timeLast*(200/moveRate.getDelay());
}
if(prize!=null)
if(points.get(0).x==prize.x && points.get(0).y==prize.y){
int newX = points.get(points.size()-1).x-(points.get(points.size()-1).x - points.get(points.size()-2).x);
int newY = points.get(points.size()-1).y-(points.get(points.size()-1).y - points.get(points.size()-2).y);
points.add(new Point(newX, newY));
if(moveRate.getDelay()>50)
moveRate.setDelay(moveRate.getDelay()-5);
prize.createPrize(PU_NONE);
prizeRate.restart();
score+=timeLast*20*eatmultiplier;
}
if(powerup!=null)
if(points.get(0).x==powerup.x && points.get(0).y==powerup.y){
int newX = points.get(points.size()-1).x-(points.get(points.size()-1).x - points.get(points.size()-2).x);
int newY = points.get(points.size()-1).y-(points.get(points.size()-1).y - points.get(points.size()-2).y);
//points.add(new Point(newX, newY)); //if powerup should increase size
powerUpPerform(powerup.getType());
if(moveRate.getDelay()>50)
moveRate.setDelay(moveRate.getDelay()-5);
//powerUpRate.restart();
score+=timeLast*20*eatmultiplier;
powerup=null;
}
p.setScore(score);
repaint();
}
});
}
}
Basically MoveRate is responsible for animation aswell "eat moves" for prizes & powerups and checks for Game Over situations.
Some other notes:
I thought this has something to do with threads which I haven't learned yet so I added this:
new Thread(new Runnable() {
public void run() {
moveRate=new MoveRate();
moveRate.start();
powerUpRate.start();
prizeRate.start();
}
}).start();
Frame still freezes.
System.gc(); doesn't work neither if I time it every 30 seconds.
Be easy with me because I'm junior student with Java :>
EDIT
I've tried to reproduce the "bug" by making the snake longer (much longer - using my final int SNAKE_INITIAL_LENGTH=200). doesn't seem to have any effect on the problem.
#Override
public void run() {
super.run();
final float timePerFrame = 1000 / Options.MAX_FPS;
float timeDiff;
while(!isInterrupted() && isRunning) {
timeDiff = System.currentTimeMillis();
mController.refresh();
timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());
try {
Thread.sleep(Math.max(Math.round(timeDiff), 0));
} catch(InterruptedException e) {
// do nothing
e.printStackTrace();
}
}
Log.e("GameThread", "Thread dead.");
}
This is what my thread is basically doing.
Options.MAX_FPS = 30;
To limit the frames per second, to have some sort of sleeping time between each refresh. The refresh method looks like this:
public synchronized void refresh() {
int mRotation = Math.round((360 + ((-1)*mAccelerometer[0] * 4.5f)) % 360);
mObject.setRotation(mRotation);
// get canvas from surfaceview
if(mSurfaceHolder != null) {
// do all calculations.
if(Looper.myLooper() == Looper.getMainLooper()) {
log("on main thread!");
} else {
log("Not on main thread");
}
Canvas mCanvas = mSurfaceHolder.lockCanvas();
if (mCanvas != null) {
// shift x offset
mScreenWidth = mCanvas.getWidth();
mScreenHeight = mCanvas.getHeight();
// draw black background, clear everything.
mCanvas.drawRect(new Rect(0,0,mScreenWidth, mScreenHeight), mBlackPaint);
// shift & draw all viewobjects if still visible
for(ViewObject view: mViewObjectList.toArray(new ViewObject[mViewObjectList.size()])) {
view.shiftX(-1 * Options.Gameplay.Environment.MOVING_SPEED);
if(view.getX() + view.getWidth() < 0) {
mViewObjectList.remove(view);
}
if(view.getCurrentBitmap() != null)
mCanvas.drawBitmap(view.getCurrentBitmap(), new Rect(0,0,view.getCurrentBitmap().getWidth(), view.getCurrentBitmap().getHeight()), new Rect(view.getX(), view.getY(), view.getX()+ view.getWidth(), view.getY()+view.getHeight()), new Paint());
view.nextFrame();
}
// draw object
final Bitmap sBitmap = mObject.getCurrentBitmap();
mObject.nextFrame();
if(sBitmap != null) {
mCanvas.drawBitmap(sBitmap, new Rect(0, 0, sBitmap.getWidth(), sBitmap.getHeight()), new Rect(mObject.getX(), mObject.getY(), sBitmap.getWidth(), sBitmap.getHeight()), new Paint());
} else log("bitmap = null!");
}
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
The thread keeps running for some time, background elements are being drawn (even though my rotation does not work quite yet, but that's another story..), the background "seems" to move (like a side-scroller), but at some random point in time, without any ADB LogCat messages (not limited to the App but the whole LogCat output) - the thread simply stops. No more drawing. Nothing. I am not calling interrupt or setting isRunning to false, as the "Thread dead." message is not written into LogCat as well..
I do not know what's happening.
Thanks for your help.
You have:
timeDiff = System.currentTimeMillis();
// refresh, which takes some time I guess
timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());
so System.currentTimeMillis() will be later and therefore bigger than timeDiff. The term in brackets will be negative - so you will be adding onto the timePerFrame and timeDiff will grow not reduce.