10. maj 2003 - 15:47
Der er
69 kommentarer og 2 løsninger
Projektopgave på HTX!!!
Vi har næsten ikke nogen erfaring inden for Java, men vi har fået til opgave at lave et program, der kan få en knap til at bevæge sig med en random funktion. Man skal så kunne klikke på knappen, og så skal den skrive oppe i hjørnet, hvor mange gange man har ramt den. Har kun haft en java i et halvt år, så der skal helst være ret udførlige beskrivelser sammen med koden. Er der nogen der vil påtage sig at lave dette program? Det haster!!! På forhånd tak!!!
Annonceindlæg fra HP
Hvis I går igang selv så vil vi meget gerne hjælpe jer når I går i stå. Både med hints og med konkrete stumper kode. Men at lave opgaven 100% for jer vil være uetisk.
Ville det ikke være bedst, hvis du selv kodede det "spil"?
Bedst jo, og vi er fuldstændig enige i at det er lidt uetisk, men nu er det sådan, at vi har to dage til at lave en rapport over programmet i, og det er ikke vores skyld, men et skift i lærer.
Hmm, der er vist én, der har "glemt" at begynder til tiden. Du/I må da have haft mere tid end 2 dage til at lave denne projektopgave i..
2 dage + 1 PC + 1 java bog + 10 liter cola + telefon nummeret til nærmeste pizzaria er også nok til den opgave !
arne v -> Ja, hvis man kan programmere java, og har en ordentlig bog, og ikke kun kopiark.
I kan jo bare begynde også spørg hvis i er lost... det er det bedste råd... "tror jeg"... jeg tror ikke der er nogle der laver opgaven 100% til jer!!
Og, nej, vi har ikke fået mere end to dage. En weekend!
http://javabog.dk er også en resource i kan trække (gratis) på.
Opgaven går vel ikke kun ud på at lave et program - det er vel bare et biprodukt.
I skal vel lave en rapport hvori i skal beskrive hvordan i er kommet frem til løsningen (eller hvordan i vil komme frem til løsningen) ??
Har i en problemformulering ?
Er der ikke nogen der kunne sætte os i gang så? Vi aner overhovedet ikke hvor vi skal begynde. Kan man ikke lave en løkke der ser nogenlunde således ud? int t = 10; int s = 0; int a; int b; int x; int y; do if (t = 10) { t = 0; a = randomNumber(-1,1); b = randomNumber(-1,1); } while(s = 0); x = x + a; y = y + b;
Tilfældige tal mellem -1 og 1: Random rng = new Random(); a = -1 + rng.nextInt(3); b = -1 + rng.nextInt(3);
if (t = 10) while(s = 0) skal nok være: if (t == 10) while(s == 0)
Men jeg tror at I skal starte med at designe jeres logik. Prøv evt. at udføre programmet på papir d.v.s. tag et stykke papir per variabel og så overstreg den gamle værdi og skriv den nye værdi hvar gang derer noget som skal ændres. Når logikken virker på papir så går I igang med at lave den i Java.
Skal programmet laves som en applet eller som en applikation ?
Som en application tror vi nok. Man skal kunne køre den via java kommandoen i dos.
Så er det en applikation.
Så er det en applikation. Er der nogle krav til om der skal bruges AWT eller SWING ? (brug SWING hvis i selv må vælge).
Grunden til at jeg nævnte det med papir er at: do { if (t == 10) { t = 0; a = -1 + rng.nextInt(3); b = -1 + rng.nextInt(3); } } while(s == 0); vil gå i uendelig løkke eller altid kun køre en gang. Løkken afsluttes når s er nul og s ændres ikke inde i løkken.
Ok, hvad er der i vejen med denne kode? import javax.swing.*; import java.awt.*; import java.awt.geom.*; public class FrameGrafik2 { public static void main(String[] arg) { GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } class GrafikFrame extends JFrame { public GrafikFrame() { setBounds(50,50,1100,700); setTitle("Min frame"); GrafikPanel panel1 = new GrafikPanel(); // Container pCon = getContentPane(); pCon.add(panel1); } class GrafikPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Random rng = new Random(); int t = 10; boolean s = true; int a = 1; int b = 1; int x = 1; int y = 1; while (s = true) { if (t == 10) { t = 0; a = -1 + rng.nextInt(3); b = -1 + rng.nextInt(3); } t = t++; x = x + a; y = y + b; Graphics2D g2 = (Graphics2D)g; Ellipse2D cirkel = new Ellipse2D.Double(x,y,50,50); g2.setPaint(Color.red); // red,green,blue, orange, yellow, pink osv g2.fill(cirkel); // Udfylder cirkel med farven red. int roed = 20; int groen = 128; int blaa = 0; g2.setPaint(new Color(roed,groen,blaa)); // [ 0-255, 0-255, 0-255] Font minFont = new Font("Courier", Font.BOLD,28); g2.setFont(minFont); g.drawString("Demo af grafik og farver og fonte",300,80); } } } }
tilføj denne import: import java.util.*;
Den kan sagtens lave den om til en *.class fil, men når jeg forsøger at køre den, er der bare en grå ramme og den tænker uafbrudt.
Ændre: while (s = true) til: while (s == true)
Det er faktisk ikke engang nok. Der skal også vær enoget som sætter s til false inden i løkken.
Det vil være nemmere at lave en JButton der flytter sig rundt end at bruge Ellipse2D.
Ok, men forstår du hvad det er vi forsøger at lave? Det er meningen at cirklen skal bevæge sig i forskellige retninger.
Ja, men det er formegentlig en pain-in-the-butt at finde ud af om musen rammer inde i cirklen eller uden for. Derfor er det nemmere med en JButton.
Den her uden while løkke skriver faltisk noget: import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.util.*; public class FrameGrafik2 { public static void main(String[] arg) { GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } class GrafikFrame extends JFrame { public GrafikFrame() { setBounds(50, 50, 850, 650); setTitle("Min frame"); GrafikPanel panel1 = new GrafikPanel(); // Container pCon = getContentPane(); pCon.add(panel1); } class GrafikPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); Random rng = new Random(); int t = 10; boolean s = true; int a = 1; int b = 1; int x = 1; int y = 1; //while (s == true) { if (t == 10) { t = 0; a = -1 + rng.nextInt(3); b = -1 + rng.nextInt(3); } t = t++; x = x + a; y = y + b; Graphics2D g2 = (Graphics2D) g; Ellipse2D cirkel = new Ellipse2D.Double(x, y, 50, 50); g2.setPaint(Color.red); // red,green,blue, orange, yellow, pink osv g2.fill(cirkel); // Udfylder cirkel med farven red. int roed = 20; int groen = 128; int blaa = 0; g2.setPaint(new Color(roed, groen, blaa)); // [ 0-255, 0-255, 0-255] Font minFont = new Font("Courier", Font.BOLD, 28); g2.setFont(minFont); g.drawString("Demo af grafik og farver og fonte", 300, 80); //} } } }
søren kan man ikke få x,y for et click ? if ( (xclick-xcenter)*(xclick-xcenter) + (yclick-ycenter)*(yclick-ycenter) <= radius * radius) {
For en cirkel jow, men det er jo en ellipse der bruges.. Men sålænge den er en cirkel så kan det bruges - hvis der ændre på nogle værdier så vil det gå galt. Jeg anbefaler bare en JButton udfra teksten: "Man skal så kunne klikke på knappen, og så skal den skrive oppe i hjørnet, hvor mange gange man har ramt den." Det vil jeg synes var nemmest. :-)
Det er nemmest ja, fordi Java så selv tester for om man har ramt knappen. (jeg kan dog godt konvertere formlen til elipse hvis det skulle være !)
Jeg kan ikke se hvordan programmet kan laves fornuftigt uden brug af tråde (en GUI tråd, dvs. main tråden, og en "flyt knap" tråd). Det er da lidt mærkeligt at udstikke en opgave af denne type ?
Jeg forestiller mig at knappen skal flytte sig i flydende bevægelser og kun ændre retning (360 grader). Hvis knappens placering er random vil man ikke have mange chancer for at ramme den - med mindre der er indlagt et pænt langt delay mellem flytene.
Ja. Enten en "100% user thread" eller en "Timer" er nok nødvendigt.
Mere praktisk skal det vel være noget a la: switch(rng.nextInt(4)) { case 0: x += k; break; case 1: x -= k; break; case 2: y += k; break; case 3: y -= k; break; } det giver 25% chance for hit. (skal lige suppleres med test for at ramme kanten)
Mon ikke man kan bruge if(cirkel.intersects(mouse_x, mouse_y, 0, 0)) { //du ramte } else { //du ramte ikke } Jeg kan ikke lige gennemskue om det evt skal være: cirkel.intersects(mouse_x, mouse_y, 1, 1)
daliwi> I har fået nogle forskellige ideer. Prøv og lig nogen af dem ind i koden. Spørg hvis der er noget I er usikre omkring. Så skal jeres kode nok begynde at tage form.
nu ved jeg ikke om jeg har forstået opgaven korrekt men her er et bud på hvordan jeg har forstået den import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.*; class KnapTest extends JFrame { JButton knap; JLabel visAntalKlik; JPanel panel; int x=0,y=0; public KnapTest() { panel = new JPanel(); knap = new JButton("tryk på mig"); knap.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ flytKnap(); } }); visAntalKlik = new JLabel("Anatal klik =0"); panel.add(knap); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(visAntalKlik,BorderLayout.NORTH); this.getContentPane().add(panel,BorderLayout.CENTER); } public void flytKnap(){ int randomX=0; int randomY=0; // lava selv koden som flytter knappen og tæller op knap.setLocation(x+randomX,y+randomY); } public static void main(String args[]) { System.out.println("Starting KnapTest..."); KnapTest mainFrame = new KnapTest(); mainFrame.setSize(400, 400); mainFrame.setVisible(true); } }
Hvis man nu hellere ville have en tekst til at bevæge sig, kunne man så benytte en Thread? Og hvordan skulle den så smides ind?
Det betyder ikke så meget om det ene eller andet der skal flyttes.
Hvis I vil have udført noget hvert sekund så kan i bl.a. lave: timer = new Timer(1000, new TimerListener()); timer.start(); class TimerListener implements ActionListener { public void actionPerformed(ActionEvent evt) { // gør noget } }
Noget kunne f.eks. være baseret på min kode ovenfor der genererer et tilfældigt tal 0,1,2 eller 3 (som så betyder højre, venstre, op og ned).
nej jeg flytter kun kanppen engang i skal selv lave koden som flytter kanppen og tæller op jeg har kun vist hvordan det kan gøres
public void flytKnap(){ Random rng = new Random(); int a = -1 + rng.nextInt(3); int b = -1 + rng.nextInt(3); x=x+(10*a); y=y+(10*b); //mangler bare at cheke om den går udenfor framen knap.setLocation(x,y); }
arne -> hvor hulen putter man den der timer ind??? Min kode ser således ud: import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.util.*; import java.awt.event.*; public class Ny3 {//1 public static void main(String[] arg) {//2 GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); }//2 }//1 class GrafikFrame extends JFrame {//3 JButton knap; JPanel panel; public GrafikFrame() {//4 Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screenSize = toolkit.getScreenSize(); setSize(800,600); Dimension selfBounds = getSize(); setLocation((screenSize.width - selfBounds.width) / 2, (screenSize.height - selfBounds.height) / 2); //Deffinerer ramens placering på skærmen setTitle("Min frame"); panel = new JPanel(); knap = new JButton("tryk på mig"); knap.addActionListener(new ActionListener(){//5 public void actionPerformed(ActionEvent ae){//6 flytKnap(); }//6 });//5 panel.add(knap); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(panel,BorderLayout.CENTER); }//4 public void flytKnap(){//7 Random rng = new Random(); int a = 0 + rng.nextInt(750); int b = 0 + rng.nextInt(550); knap.setLocation(a,b); }//7 }//3
Jeg vil sige i bunden af framens constructor.
package test; import javax.swing.*; import java.awt.*; import java.util.*; import java.awt.event.*; public class Ny3 { public static void main(String[] arg) { GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } class GrafikFrame extends JFrame { JButton knap; JPanel panel; public GrafikFrame() { Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screenSize = toolkit.getScreenSize(); setSize(800, 600); Dimension selfBounds = getSize(); setLocation( (screenSize.width - selfBounds.width) / 2, (screenSize.height - selfBounds.height) / 2); //Deffinerer ramens placering på skærmen setTitle("Min frame"); panel = new JPanel(); knap = new JButton("tryk på mig"); knap.addActionListener(new ActionListener() { //5 public void actionPerformed(ActionEvent ae) { //6 flytKnap(); } }); panel.add(knap); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(panel, BorderLayout.CENTER); javax.swing.Timer timer = new javax.swing.Timer(1000, new TimerListener()); timer.start(); } public void flytKnap() { Random rng = new Random(); int a = 0 + rng.nextInt(750); int b = 0 + rng.nextInt(550); knap.setLocation(a, b); } class TimerListener implements ActionListener { public void actionPerformed(ActionEvent evt) { flytKnap(); } } }
Burde det ikke virke hvis jeg skrev således nede i bunden? }//7 timer = new Timer(1000, new TimerListener()); timer.start(); class TimerListener implements ActionListener { public void actionPerformed(ActionEvent evt) { flytKnap(); } } }//3
Hvad hvis man skal resette timeren hver gang man trykker på knappen? Man kan ikke få fat i variablen timer, når man er under klassen flytknap().
Flyt erklæring af Timer timer op i klassen så den kan access fra actionListener'en og kald timer.restart() !
Er der nogen der kan fortælle os, hvorfor hulen den ikke vil tælle op hvor mange gange man har trykket på knappen? import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.util.*; import java.awt.event.*; public class Ny4 {//1 public static void main(String[] arg) {//2 GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); }//2 }//1 class GrafikFrame extends JFrame {//3 JButton knap; JPanel panel; boolean stop = false; int taeller; javax.swing.Timer timer = new javax.swing.Timer(2000, new TimerListener()); public GrafikFrame() {//4 Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screenSize = toolkit.getScreenSize(); setSize(800,600); Dimension selfBounds = getSize(); setLocation((screenSize.width - selfBounds.width) / 2, (screenSize.height - selfBounds.height) / 2); //Deffinerer ramens placering på skærmen setTitle("Min frame"); knap = new JButton("tryk på mig"); timer.start(); panel = new JPanel(); knap.addActionListener(new ActionListener(){//5 public void actionPerformed(ActionEvent ae){//6 taeller++; flytKnap(); }//6 });//5 JLabel visAntalKlik = new JLabel("Anatal klik = " + taeller); panel.add(knap); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(panel,BorderLayout.CENTER); this.getContentPane().add(visAntalKlik,BorderLayout.NORTH); }//4 public void flytKnap() {//7 Random rng = new Random(); int a = 0 + rng.nextInt(700); int b = 0 + rng.nextInt(525); knap.setLocation(a,b); timer.restart(); System.out.println(taeller); }//7 class TimerListener implements ActionListener {//8 public void actionPerformed(ActionEvent evt) {//9 flytKnap(); }//9 }//8 }//3
taeller bliver fint talt op ! Men visAntalKlik labellen bliver ikke opdateret. I skalhave den opdateret hver gang i inkrementerer taeller.
Ja, præcis, men har du nogen ide om hvordan? Har snart prøvet alt.
Noget i retning af: visAntalKlik.setText("Anatal klik = " + taeller); Den skal bare sættes ind det rigtige sted og så skal visAntalKlik erklæres det rigtige sted.
Jeg har lavet min fortolkning af spillet her: import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; public class Main { public static void main(String args[]) { new BallGame().show(); } } class BallGame extends JFrame implements WindowListener, MouseListener, Runnable { private int frameWidth = 640; private int frameHeight = 480; private boolean doubleBuffered = true; private Image offscreen; private int width=-1; private int height=-1; private Thread internalThread; private boolean running = true; private Ellipse2D circle; private double circle_x = frameWidth / 2; private double circle_y = frameHeight / 2; private int circle_size = 15; private int circle_angle = 0; private int circle_angle_count = 0; private int circle_speed = 4; private int hits = 0; public BallGame() { createFrame(); internalThread = new Thread(this); internalThread.start(); } private void createFrame() { setTitle("Ballgame"); addWindowListener(this); addMouseListener(this); //Center Frame java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); setSize(new java.awt.Dimension(frameWidth, frameHeight)); setLocation( (screenSize.width-this.getWidth()) / 2, (screenSize.height - this.getHeight()) / 2); } public void update(Graphics g) { if(doubleBuffered) updateDoubleBufffered(g); else super.update(g); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; circle = new Ellipse2D.Double(circle_x, circle_y, circle_size, circle_size); g2.setPaint(Color.red); g2.fill(circle); g2.setPaint(Color.black); g2.drawString("Du har ramt: " + hits + " gange", 10, 40); } private void updateDoubleBufffered(Graphics g) { Dimension d = getSize(); if(offscreen == null || width!=d.width || height!=d.height || offscreen==null) { width = d.width; height = d.height; if(width>0 || height>0) offscreen = createImage(width, height); else offscreen = null; } if (offscreen == null) return; Graphics gg = offscreen.getGraphics(); gg.setColor(getBackground()); gg.fillRect(0, 0, width, height); gg.setColor(getForeground()); paint(gg); gg.dispose(); g.drawImage(offscreen, 0, 0, null); } public void run() { while(running) { try { circle_angle_count++; if(circle_angle_count > 25) { circle_angle = (int)(Math.random() * 35) * 10; circle_angle_count = 0; } circle_x += circle_speed * Math.cos(Math.toRadians(circle_angle)); circle_y += circle_speed * Math.sin(Math.toRadians(circle_angle)); if(circle_x < 0) { if(circle_angle>180) circle_angle -= 180; else circle_angle += 180; } if(circle_x > frameWidth) { if(circle_angle>270) circle_angle -= 180; else circle_angle += 180; } if(circle_y < 0) { circle_angle -= 180; } if(circle_y > frameHeight) { circle_angle += 180; } repaint(); Thread.sleep(5); } catch(InterruptedException e) { e.printStackTrace(); } } } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseClicked(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON1) { int mouse_x = e.getX(); int mouse_y = e.getY(); double temp_x = circle_x + (circle_size / 2); double temp_y = circle_y + (circle_size / 2); if((mouse_x - temp_x) * (mouse_x - temp_x) + (mouse_y - temp_y) * (mouse_y - temp_y) <= circle_size * circle_size) { hits++; } } } public void windowOpened(WindowEvent e){} public void windowClosing(WindowEvent e){ dispose(); System.exit(0);} public void windowClosed(WindowEvent e){} public void windowIconified(WindowEvent e){} public void windowDeiconified(WindowEvent e){} public void windowActivated(WindowEvent e){} public void windowDeactivated(WindowEvent e){} } Hvem får højeste score ? ;-)
Må man ændre: Thread.sleep(5); ? :-)
Det er nemmere at lade være med at starte tråden :-) Men så vil man finde udaf at collisionskoden ikke er helt optimal.. (Man skal så lige tilføje en repaint();) if((mouse_x - temp_x) * (mouse_x - temp_x) + (mouse_y - temp_y) * (mouse_y - temp_y) <= circle_size * circle_size) { hits++; repaint(); }
Den her version er rigtig svær at få en høj score med: import javax.swing.*; import java.awt.*; import java.util.*; import java.awt.event.*; public class Ny4 { public static void main(String[] arg) { GrafikFrame frame = new GrafikFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.show(); } } class GrafikFrame extends JFrame { private JButton knap; private JPanel panel; private JLabel visAntalKlik; private boolean stop = false; private int taeller; private Random rng = new Random(); private javax.swing.Timer timer = new javax.swing.Timer(2000, new TimerListener()); public GrafikFrame() { Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screenSize = toolkit.getScreenSize(); setSize(800, 600); Dimension selfBounds = getSize(); setLocation( (screenSize.width - selfBounds.width) / 2, (screenSize.height - selfBounds.height) / 2); setTitle("Min frame"); knap = new JButton("tryk på mig"); timer.start(); panel = new JPanel(); knap.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { taeller++; visAntalKlik.setText("Antal klik = " + taeller); timer.setInitialDelay(2000/taeller); flytKnap(); } }); visAntalKlik = new JLabel("Antal klik = " + taeller); panel.add(knap); this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(panel, BorderLayout.CENTER); this.getContentPane().add(visAntalKlik, BorderLayout.NORTH); } public void flytKnap() { int a = rng.nextInt(700); int b = rng.nextInt(525); knap.setLocation(a, b); timer.restart(); } class TimerListener implements ActionListener { public void actionPerformed(ActionEvent evt) { flytKnap(); } } }
Jeg har da lige fået 25 ! (Men jeg kom vist nok også til at tryke på space..)
Det er nogle lækre svar i er kommet med, og i skal nok få point, men vi arbejder lige færdig med projektet. Er der forøvrigt nogen der kan fortælle os, hvorfor knappen bliver ved med at vende tilbage til startpositionen, hver gang man trykker på den? Den skulle jo bare køre en randomfunktion...
Det har jeg også observeret. Tilsyneladende får click den til at ryge tilbage til NORTH.
Nej, det er på grund af: visAntalKlik.setText("Antal klik = " + taeller); Hvis man slår den fra, så virker den. Men det er da ulogisk?
Tja - det syne sjeg også. Jeg tror dog stadig at problemet skyldes mix af layout managers og setLocation.
02. juni 2003 - 20:27
#68
??
05. juni 2003 - 16:44
#69
Undskyld at vi ikke har svaret tilbage, men vi har haft utrolig travlt med eksamen osv. Ja vi kom videre, og vi udskiftede JLabelen med en almindelig Label, hvilket løste vores lille problem. Samtidig så kan vi fortælle, at vi fik 9 for vores projekt, og at vi er jer alle utrolig taknemmelige.
05. juni 2003 - 16:47
#70
Tillykke med det.
05. juni 2003 - 17:39
#71
Det var da dejligt. Også tillykke herfra.
Kurser inden for grundlæggende programmering