עבור לתוכן

Java| Double Buffering

Featured Replies

פורסם

היי,

אני מתכנת כרגע משחק SNAKE ויש לי בעיה עם מימוש double buffering כדי שהמשחק יהיה חלק יותר ולא יקפוץ כל שניה.

זה הקוד:



public class Snake extends JFrame implements KeyListener, Runnable {

//Variabales:
private JMenuBar menubar ;
private JMenu game, instructions, help ;
private JPanel p1, p2 ;
private JTextArea t ;

private ImageIcon cube = new ImageIcon ("scube.png") ; // The icons that creats the snake.
private ImageIcon [] sc = new ImageIcon [500] ; // Array of images that will create the snake.
private JLabel [] scj = new JLabel [500] ; //Array of labels that will store each cube.
private int [] scx = new int [500] ; // The x coordinate of the cubes.
private int [] scy = new int [500] ; // The y coordinate of the cubes.
private final int cb = 10 ; // The size of each cube.
private int c ; // counts the cubes - the length of the snake.
private boolean mover, movel, moveu, moved ; // To wich direction the snake is able to move.
private int xDirection, yDirection ; // Change snakes direction.
private Point [] scp = new Point [500] ;// The order of the points that the snake have to reach.
private int x, y ; // The diameters of the screen.
private final int speed = 50 ; // The speed of the game.


Snake () {

// Creates a screen to run the game
createGameWindow () ;
// Initialize the variabales
initializeValues () ;
// Creates the snake
createSnake () ;

addKeyListener (this) ;
// Threads
Thread t1 = new Thread (this) ;
t1.run () ;

}

public void initializeValues () {
c = 3 ;
scx [0] = 300 ;
scy [0] = 200 ;
movel = false ;
mover = true ;
moveu = true ;
moved = true ;
xDirection = 10 ;
yDirection = 0 ;
x = 700 ;
y = 500 ;
}


public void createGameWindow () {

//Window properties
setVisible (true) ;
setSize (700,500) ;
setResizable (false) ;
setTitle ("Snake") ;
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE) ;

//Menu bar
menubar = new JMenuBar () ;
setJMenuBar (menubar) ;
game = new JMenu ("Game") ;
instructions = new JMenu ("Instructions") ;
help = new JMenu ("help") ;
menubar.add (game) ;
menubar.add (instructions) ;
menubar.add (help) ;

JMenuItem newgame = new JMenuItem ("New game") ;

newgame.addActionListener (

new ActionListener () {

public void actionPerformed (ActionEvent e) {
//Write commend here
}
}) ;
game.add (newgame) ;

//Panel
p1 = new JPanel (null) ;
p1.setBackground(Color.WHITE) ;
add (p1) ;
p2 = new JPanel () ;
p2.setLayout(new GridLayout(0, 1));
p2.setBackground(Color.BLACK) ;
add (p2, BorderLayout.SOUTH) ;

//Scores
t = new JTextArea ("Points:") ;
t.setEnabled(false) ;
t.setBackground(Color.BLACK) ;
p2.add (t) ;

}

public void createSnake () {

for (int i=0 ; i < 3 ; i++) {
sc [i] = new ImageIcon () ;
sc = cube ;
scj = new JLabel (sc) ;
p1.add ( scj ) ;
scj.setBounds(scx , scy , cb, cb) ;
scx [i+1] = scx - 10 ;
scy [i+1] = scy ;
}

}

public void move () {

for (int i = 0 ;i < c ; i++)
scp = scj .getLocation() ;

scx [0] += xDirection ;
scy [0] += yDirection ;
scj[0].setBounds(scx[0], scy[0], cb, cb) ;

for (int i = 1 ; i< c ; i++)
scj .setLocation( scp[i-1] ) ;

if (scx [0] == x )
scx [0] = 10 ;
else if (scx[0] == 0)
scx [0] = x -10 ;
else if (scy[0] == y)
scy [0] = 10 ;
else if (scy[0] == 0)
scy [0] = y -10 ;

p1.repaint() ;
}

public void keyPressed (KeyEvent e) {

int keyCode = e.getKeyCode() ;
// Snake moves to left when the player press left arrow
if (mover && keyCode == e.VK_RIGHT) {
xDirection = 10 ;
yDirection = 0 ;
movel = false ;
mover = true ;
moveu = true ;
moved = true ;
}
// Snake moves to right when the player press right arrow
if (movel && keyCode == e.VK_LEFT) {
xDirection = -10 ;
yDirection = 0 ;
movel = true ;
mover = false ;
moveu = true ;
moved = true ;
}
// Snake moves up when the player press to up arrow
if (moveu && keyCode == e.VK_UP) {
xDirection = 0 ;
yDirection = -10 ;
movel = true ;
mover = true ;
moveu = true ;
moved = false ;
}
// Snake moves to down when the player press down arrow
if (moved && keyCode == e.VK_DOWN) {
xDirection = 0 ;
yDirection = 10 ;
movel = true ;
mover = true ;
moveu = false ;
moved = true ;
}
}

public void keyReleased (KeyEvent e) {
}

public void keyTyped (KeyEvent e) {
}

public void run () {

while (true) {
move () ;
try {
Thread.sleep (speed) ;
}
catch (InterruptedException ie) {
System.out.println ("Error") ;
}
}
}


}

אשמח לעזרה, תודה רבה smile.gif

פורסם

לא כלכך יצא לי לעבוד בצורה רצינית עם swing אבל נראה לי שהוא כבר תומך ב double buffering...

נראה לי מה שהורג אותך פה זה הלולאה של המשחק. ספציפית השימוש ב Thread.sleep.

קודם כל, התרד שלך יתעורר רק כשהמעבד פנוי להריץ אותו.

דבר שני, אתה ישן 50 מלי שניות ( speed = 50 ) כל איטרציה,

מה שמגביל אותך ל FPS של 20 ( 1000/50 ) וזה בלי הזמן

שאתה מבזבז לחשב ולרנדר.

חפש ברשת איך לבנות לולאת משחק, זה נושא שנטחן כבר מכל זווית.

אה ויש לך frameworks מצויינים למשחקי 2D ב java או לפחות תשתמש ב java2D זה אחלה API והוא בא bulitin. תהנה :)

עריכה:

מצאתי הסבר מפורט ב JGO :

http://www.java-gaming.org/index.php?topic=24220.0

פורסם
  • מחבר

לא כלכך יצא לי לעבוד בצורה רצינית עם swing אבל נראה לי שהוא כבר תומך ב double buffering...

נראה לי מה שהורג אותך פה זה הלולאה של המשחק. ספציפית השימוש ב Thread.sleep.

קודם כל, התרד שלך יתעורר רק כשהמעבד פנוי להריץ אותו.

דבר שני, אתה ישן 50 מלי שניות ( speed = 50 ) כל איטרציה,

מה שמגביל אותך ל FPS של 20 ( 1000/50 ) וזה בלי הזמן

שאתה מבזבז לחשב ולרנדר.

חפש ברשת איך לבנות לולאת משחק, זה נושא שנטחן כבר מכל זווית.

אה ויש לך frameworks מצויינים למשחקי 2D ב java או לפחות תשתמש ב java2D זה אחלה API והוא בא bulitin. תהנה :)

עריכה:

מצאתי הסבר מפורט ב JGO :

http://www.java-gaming.org/index.php?topic=24220.0

תודה על העזרה אבל אני מתקשה להבין איך לאחד את השימוש הנכון בלולאה כפי שמופיע בכתובת שציינת עם הקוד שלי.

אני לא כ"כ מצליח להבין את זה, אשמח להסבר :)

פורסם

משהו ספציפי שעושה לך צרות?

בנתיים הנה משהו פשוט שאמור לעבוד:


class MySnakeGame
{
public static const int FPS = 30;
private boolean running;


public void mainLoop()
{
const double step = 100 / FPS;
long deltaTime;
long sleep;
long time;


while (running)
{
time = System.currentTimeMillis();


move();
repaint();


deltaTime = System.currentTimeMillis() - time;
sleep = step - deltaTime;


Thread.sleep((sleep > 0) ? sleep : 1); // clamp sleep time if update takes too long
}
}
}

כמה דברים לגבי הקוד:

1. זו דרך מאוד נאבית לבנות לולאת משחק, אבל זה יתן לך נקודת התחלה.

2. אני לא בטוח אם repaint() חוזר מיד (כלומר מרנדר ב thread נפרד) ... זו יכולה להיות בעיה, בכל מקרה תעבור ל java2D.

3. לא הרצתי את הקוד, מתנצל מראש על שגיאות תחביר :P

4. אה והרגע קלטתי שאני לא תופס exception ב sleep אז תקן את זה..

פורסם
  • מחבר

תודה, שיניתי את הלופ למה שנתת,

הכל עובד אבל לא השתנה שום דבר שנראה לעין, הנחש עדיין זז בפלאשים כאלה כאילו אין double buffering .

פורסם

זה כנראה בגלל שאתה מזיז אותו מספר פיקסלים כל פריים או כל מספר פריימים, בלי אינטרפלציה.

שזה מילה מופלצת להגיד ערכים באמצע - נגיד ותועלת שלך זזה 30 פיקסלים בשניה, ונגיד אתה רץ ב 30 FPS.

איפה היא תהיה בפריים ה 21 ? הצצתי שוב בקוד שלך, ועם ה loop החדש זה נראה שהנחש שלך היה צריך לעוף, כי אתה

מזיז אותו 10 פיקסלים כל פריים...

לא חושב ש double buffering זו הבעיה פה. זה מונע תופעה מעצבנת בשם tearing. אתה תראה את המסך סוג של נחצה

לשניים כמו פה, זה בגלל שאתה מעדכן את ה buffer שממנו אתה מצייר. פלאשים זה לא חלק מהסיפור.

אגב, תעזור לך דוגמה פשוטה עם java2D ?

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים