Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (521)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (589)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Is this a good foundation?  (Read 1427 times)
0 Members and 1 Guest are viewing this topic.
Offline AR

Junior Newbie





« Posted 2011-09-29 15:55:28 »

Hi, I'm new. Cheesy Looks like a great community. I was considering posting this in the newbies/problems section but I get the idea this one might be more suitable. Would appreciate a move if it's wrong.

So, I'm looking to create a relatively basic game in Java2D. I know, I've looked into Slick/Pulp a bit and it may make it easier, but I want to try Java2D and my own classes first. Some may call it a waste of time, I see it more as an academic persuit. Wink If I max out Java2D's capabilities, then great I've understood it, but I don't aim on getting near that point anyway.

At first I was using a basic buffered image as a back buffer and using "passive" rendering, and a very basic game loop. I then read up a bit on active rendering techniques (including buffer strategies, which I didn't even realise could be used in applets!) and using a more sophisicated way of controlling game speed. Before, the inaccuracies of the timing method became more and more pronounced as you wanted the game to speed up. There is a danger of it becoming totally out of sync with the rendering at high speeds.

This forum has been a great help, especially Gudradain and ra4king with the loop/rendering (I hope you don't mind Wink).

I'd be grateful for any feedback/criticism of this basic functionality before I get deeper into the game's development and find I may have to go back and alter a lot of stuff (though I'm sure this will inevitably happen anyway...). I've just commented on some stuff to help me try to understand what's going on. Maybe it'll be useful for other newbies as well!

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
package games;

import java.applet.Applet;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;

public class GameApplet extends Applet implements Runnable, MouseListener{
    //<editor-fold defaultstate="collapsed" desc="class declarations">
    static int width = 800;
    static int height = 600;
    Canvas canvas;
    BufferStrategy bufferStrategy;
    boolean running = true;

    //game loop control
    long desiredFPS = 60;
    long desiredDeltaLoop = (1000*1000*1000)/desiredFPS;

    Thread gameloop;
    ImageEntity background; //a class that loads images for use

    int frameCount = 0;
    int frameRate = 0;
    long startTime = System.currentTimeMillis();
    //</editor-fold>

    @Override
    public void init() {
        background = new ImageEntity(this); //uses external class as an image loader
        background.load("bg.jpg");
        System.out.println("loaded background"); //testing
        if (bufferStrategy == null) {
            setPreferredSize(new Dimension(width, height));
            this.setSize(new Dimension(width, height));
            this.setIgnoreRepaint(true); //ensure os does not interfere in painting

            canvas = new Canvas();
            canvas.setBounds(0, 0, width, height);

            canvas.setIgnoreRepaint(true);
            add(canvas);
            canvas.createBufferStrategy(2); //create front+back buffer
            bufferStrategy = canvas.getBufferStrategy(); //link the canvas to that strategy
            canvas.requestFocus();
        }
    }

    @Override
    public void start() {
        gameloop = new Thread(this);
        gameloop.start();
        running = true;
    }

    @Override
    public void run() {
        // thread run event (game loop)
        long beginLoopTime;
        long endLoopTime;
        long currentUpdateTime = System.nanoTime();
        long lastUpdateTime;
        long deltaLoop;

        while (!isActive()) {
            Thread.yield();//wait on the thread if applet is not active/visible
        }
        while (running) {
            beginLoopTime = System.nanoTime(); //time before render
            render(); //draw objects onto the canvas/buffer
            lastUpdateTime = currentUpdateTime;
            currentUpdateTime = System.nanoTime();
            update((int) ((currentUpdateTime - lastUpdateTime) / (1000 * 1000))); //update the game logic with this speed
            endLoopTime = System.nanoTime();
            deltaLoop = endLoopTime - beginLoopTime;

            //I know this may be inaccurate due to Milliseconds, but it's good enough for me for now
            //<editor-fold defaultstate="collapsed" desc="fps calculation">
            frameCount++;
            if (System.currentTimeMillis() > startTime + 1000) {//if a second passes
                startTime = System.currentTimeMillis();//update to this second
                frameRate = frameCount;
                System.out.println(frameRate);
                frameCount = 0;
            }
            //</editor-fold>

            //<editor-fold defaultstate="collapsed" desc="synchronisation">
            if (deltaLoop > desiredDeltaLoop) {
                //Do nothing. We are already late.
            } else {
                try {
                        Thread.sleep((desiredDeltaLoop - deltaLoop) / (1000 * 1000));
                } catch (InterruptedException e) {
                   }
            }
            if (!isActive()) {
                System.out.println("Inactive"); //testing
                return;
            }
            //</editor-fold>
        }
    }

    @Override
    public void stop() {
        running = false;//is this really necessary or would the thread cease on its own if running is already false elsewhere?
                        //volatile?
    }

    public void render() {
        try {
            do {
                do {
                    Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics(); //creates a g2d object, takes graphics context from strategy
                       render(g); //draw
                    g.dispose(); //manually free up resources
                } while (bufferStrategy.contentsRestored()); //buffer contents restored since being lost
                bufferStrategy.show();
            } while (bufferStrategy.contentsLost());  //has the buffer been restored?
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    public void update(int deltaTime){
         //update game logic

    }

    protected void render(Graphics2D g) {
        g.drawImage(background.getImage(), 0, 0, this); //returns an image and draws it onto the context

    }

     @Override
    public void mouseClicked(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void mousePressed(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void mouseExited(MouseEvent e) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}
Offline ra4king

JGO Kernel


Medals: 355
Projects: 3
Exp: 5 years


I'm the King!


« Reply #1 - Posted 2011-10-01 04:52:45 »

It looks really good so far!
Really feels good to have helped someone out there on the interwebz Smiley

Thoughts:
1. The "running" variable is unnecessary since all threads are killed as soon as the applet is closed.
2. For accurate System.currentTimeMillis() readings, use this trick in init():
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
if(System.getProperty("os.name").startsWith("Win")) {
    new Thread() {
        {
            setDaemon(true);
            start();
        }

        public void run() {
            while(true) {
                try {
                    Thread.sleep(Long.MAX_VALUE);
                }
                catch(Exception exc) {}
            }
        }
    }
}

3. Thread.sleep is fine for now, but for a smoother game loop, consider using Thread.yield (smoother, hogs CPU) or Thread.sleep(1) (less smooth, less CPU) in a while loop:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis()-startTime < sleepTime) {
    if(useYield)
        Thread.yield();
    else
        try {
            Thread.sleep(1);
        }
        catch(Exception exc) {}
}

Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #2 - Posted 2011-10-01 05:56:54 »

Looks good, but you might want to put the MouseListener in another class or you'll end up with a huge general Game class in the end. I'd create an input manager or something.

Myomyomyo.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline AR

Junior Newbie





« Reply #3 - Posted 2011-10-01 13:19:45 »

Thanks muchly for your responses! Smiley
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xFryIx (58 views)
2014-11-13 12:34:49

digdugdiggy (36 views)
2014-11-12 21:11:50

digdugdiggy (30 views)
2014-11-12 21:10:15

digdugdiggy (24 views)
2014-11-12 21:09:33

kovacsa (48 views)
2014-11-07 19:57:14

TehJavaDev (51 views)
2014-11-03 22:04:50

BurntPizza (51 views)
2014-11-03 18:54:52

moogie (66 views)
2014-11-03 06:22:04

CopyableCougar4 (64 views)
2014-11-01 23:36:41

DarkCart (150 views)
2014-11-01 14:51:03
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!