java - Reference of graphics 2d object doesn't work in orphan Thread -
i trying design simple game using graphics2d
in jpanel. able draw normal objects overriding paintcomponent()
method. when reference graphics2d object inside orphan thread, not work. going wrong?
public void paintcomponent(graphics g) { super.paintcomponent(g); g2d = (graphics2d) g; g2d.drawstring("sample",60,100); //works fine if(<certain condition>){ new thread(new runnable(){ //some code here public void run() { try{ g2d.drawstring("sample2",60,100); //does not work.. :( system.out.println("test print"); //shows output } catch (exception e) { } } }).start(); } }
here complete code reference. 'ping pong ball' game. working not able highlight increase in score when ball hits striker. important part of code highlighted. it's sscce.
import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.random; public class movingball extends jpanel { int xpos, ypos; int speedx, speedy; int diameter; private jbutton jbutton1 = new jbutton(); private jbutton jbutton2 = new jbutton(); private jlabel jlabel1 = new jlabel(); private static timer timer; private static movingball movingball; private int w,h; private int strikerheight; private int strikerwidth; private int score; private boolean isballmoving; int strikerypos; graphics2d g2d; public movingball() { //striker properties strikerheight = 100; strikerwidth = 20; strikerypos = strikerheight/2; //ball properties isballmoving = false; xpos = strikerwidth + 5; ypos = 0; random r = new random(); speedx = 2+ math.abs(r.nextint()) % 5; speedy = 2+ math.abs(r.nextint()) % 5; diameter = 50; //ui objects try { jbinit(); } catch (exception e) { e.printstacktrace(); } movingball = this; //helps access current class object in inner classes //create timer animation timer = new timer(1, new actionlistener() { public void actionperformed(actionevent evt) { movingball.repaint(); } }); timer.start(); } public void paintcomponent(graphics g) { super.paintcomponent(g); g2d = (graphics2d) g; dimension size = getsize(); insets insets = getinsets(); w = size.width - insets.left - insets.right; h = size.height - insets.top - insets.bottom; //paint striker g2d.setcolor(color.dark_gray); if(strikerypos < strikerheight/2) //top end g2d.fillrect(0,0, strikerwidth, strikerheight); else if(strikerypos > (h-strikerheight/2)) //bottom end g2d.fillrect(0,h-strikerheight, strikerwidth, strikerheight); else //anywhere in middle g2d.fillrect(0,strikerypos - (strikerheight/2), strikerwidth, strikerheight); //paint ball if (isballmoving) { xpos += speedx; ypos += speedy; g2d.drawoval(xpos, ypos, diameter,diameter); if((xpos+diameter) >= w) { //speedx *= -1; speedx = ((int)math.signum((double)speedx))*(-1) * (2+ math.abs(new random().nextint()) % 5); xpos = w-diameter-1; } if(xpos <= strikerwidth) { if((ypos+diameter/2) >= (strikerypos-strikerheight/2) && (ypos+diameter/2) <= (strikerypos+strikerheight/2)) { score++; ////////////////////////////////////////////////////////////////////// /////this part focus on/////////////////////////////////////// /////when ball hits striker, show '+1' text fading upwards point of hit /////(this highlight +1 increase in score)/////////////////// //////now since ball may hit striker again before previous +1 has faded, //////i have made simple thread create +1 every time there hit. there can multiple //////+1 on screen. //-------------------------------sadly, wrong------------------- //print '+1' show score increase new thread(new runnable(){ int ystart = strikerypos; int fadelength = 0; timer pointtimer; int max_fade_len = 50; public void run() { try { pointtimer = new timer(1, new actionlistener() { public void actionperformed(actionevent evt) { if(fadelength >= max_fade_len) pointtimer.stop(); g2d.setcolor(new color(0,0,0,255)); g2d.setfont(new font("times",font.bold,20)); g2d.drawstring("+1",60,ystart - fadelength); g2d.drawoval(100,100,50,50); system.out.println("drawn +1 @ x = " + 60 + " y = " + (ystart - fadelength)); fadelength++; } }); pointtimer.start(); } catch (exception e) { } } }).start(); ////////////////thread ends here////////////////////// } else { score--; } //show score on label jlabel1.settext("score: " + score); speedx = ((int)math.signum((double)speedx))*(-1) * (2+ math.abs(new random().nextint()) % 5); xpos = strikerwidth+1; } if(ypos <= 0) { speedy = ((int)math.signum((double)speedy))*(-1) * (2+ math.abs(new random().nextint()) % 5); ypos = 0; } if((ypos+diameter) >= h) { speedy = ((int)math.signum((double)speedy))*(-1) * (2+ math.abs(new random().nextint()) % 5); ypos = h-diameter; } } else { g2d.drawoval(xpos,ypos,diameter,diameter); return; } } public static void main(string[] args) { jframe frame = new jframe("magic ball"); movingball = new movingball(); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.add(movingball); frame.setsize(450, 700); frame.setlocationrelativeto(null); frame.setvisible(true); } private void jbinit() throws exception { jbutton1.settext("start"); jbutton1.addactionlistener(new actionlistener() { public void actionperformed(actionevent e) { jbutton1_actionperformed(e); } }); jbutton2.settext("stop"); jbutton2.addactionlistener(new actionlistener() { public void actionperformed(actionevent e) { jbutton2_actionperformed(e); } }); jlabel1.settext("score:0"); this.add(jbutton1, null); this.add(jbutton2, null); this.add(jlabel1, null); this.setbackground(color.white); this.addmousemotionlistener(new mousemotionlistener() { public void mousemoved(mouseevent e) { int coordx = e.getx(); if(coordx < 200) strikerypos = e.gety(); } public void mousedragged(mouseevent e) { } }); } private void jbutton1_actionperformed(actionevent e) { if(!isballmoving) isballmoving = true; } private void jbutton2_actionperformed(actionevent e) { isballmoving = false; } }
i don't think many people consider 250 loc 'short' (though must admit deliberately vague when writing sscce document). otoh adapted shorter source seen here animated example shows 'fade effect' on mouse clicks. adapting needs left exercise ..you.
this source shows how change drawn string on period of 5 seconds. uses same thread
(the edt) both main (bouncing ball) , fade animation.
import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.bufferedimage; import java.util.arraylist; import javax.swing.*; class shapecollision { private bufferedimage img; private area walls; int x; int y; int xdelta = 3; int ydelta = 2; arraylist<strike> strikes; /** * method determine if 2 instances of area intersect */ public boolean doareascollide(area area1, area area2) { boolean collide = false; area collide1 = new area(area1); collide1.subtract(area2); if (!collide1.equals(area1)) { collide = true; } area collide2 = new area(area2); collide2.subtract(area1); if (!collide2.equals(area2)) { collide = true; } return collide; } shapecollision() { int w = 400; int h = 200; img = new bufferedimage(w, h, bufferedimage.type_int_rgb); final jlabel imagelabel = new jlabel(new imageicon(img)); x = w / 2; y = h / 2; strikes = new arraylist<strike>(); mouselistener strikelistener = new mouseadapter() { @override public void mouseclicked(mouseevent e) { strike s = new strike(e.getpoint(),system.currenttimemillis()); strikes.add(s); } }; imagelabel.addmouselistener(strikelistener); walls = new area(new rectangle(0, 0, w, h)); actionlistener animate = new actionlistener() { @override public void actionperformed(actionevent e) { animate(); imagelabel.repaint(); } }; timer timer = new timer(50, animate); timer.start(); joptionpane.showmessagedialog(null, imagelabel); timer.stop(); } public void animate() { graphics2d g = img.creategraphics(); g.setrenderinghint( renderinghints.key_antialiasing, renderinghints.value_antialias_on); g.setcolor(color.black); g.fillrect(0, 0, img.getwidth(), img.getheight()); x += xdelta; y += ydelta; int s = 15; area player = new area(new ellipse2d.double(x, y, s, s)); // acid test of edge collision; if (doareascollide(player, walls)) { if (x + s > img.getwidth() || x < 0) { xdelta *= -1; } if (y + s > img.getheight() || y < 0) { ydelta *= -1; } } g.setcolor(color.orange); g.setcolor(color.yellow); g.fill(player); (strike strike : strikes) { strike.draw(g); } g.dispose(); } public static void main(string[] args) { runnable r = new runnable() { @override public void run() { new shapecollision(); } }; // swing guis should created , updated on edt // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html swingutilities.invokelater(r); } } class strike { private point point; private long started; private final long duration = 5000; private boolean expired = false; strike(point point, long time) { this.point = point; started = time; } public void draw(graphics g) { long = system.currenttimemillis(); long age = - started; if (age>duration) { expired = true; return; } double fraction = 1d-((double)age/(double)duration); int alpha = (int)(fraction*255d); color c = new color(255,255,255,alpha); g.setcolor(c); string s = point.x + "," + point.y; g.drawstring( s, point.x, point.y ); } public boolean isexpired() { return expired; } }
Comments
Post a Comment