עבור לתוכן
View in the app

A better way to browse. Learn more.

HWzone

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

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 ?

ארכיון

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

דיונים חדשים

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.