import javafx.ui.*; import javafx.ui.canvas.*; import java.lang.System; import javax.swing.Timer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.Thread; import java.lang.Exception; class Bat { attribute x: Number; attribute y: Number; attribute width: Number; attribute height: Number; attribute color: Color; } class WinInfo { attribute hits: Integer; attribute miss: Integer; attribute message: String; } attribute WinInfo.hits = 0; attribute WinInfo.miss = 0; attribute WinInfo.message = "Click the mouse to start"; class Ball { attribute x: Integer; attribute y: Integer; attribute nextX: Integer; attribute nextY: Integer; attribute step: Integer; attribute heading: Integer; attribute speed: Integer; attribute maxY: Integer; attribute minY: Integer; operation beregnNext(); operation headingSkiftY(); operation headingSkiftX1(); operation headingSkiftX2(); operation move(); } operation Ball.beregnNext() { if (heading == 1) { if(y >= minY + 2) { nextY = y - speed; nextX = x + speed; } else { headingSkiftY(); } } else if (heading == 2) { nextX = x + speed; } else if (heading == 3) { if(y <= maxY - 2) { nextY = y + speed; nextX = x + speed; } else { headingSkiftY(); } } else if (heading == 4) { if(y <= maxY - 2) { nextY = y + speed; nextX = x - speed; } else { headingSkiftY(); } } else if (heading == 5) { nextX = x - speed; } else if (heading == 6) { if(y >= minY + 2) { nextY = y - speed; nextX = x - speed; } else { headingSkiftY(); } } else { return; } } operation Ball.headingSkiftY() { if (heading == 1) { heading = 3; } else if (heading == 2) { heading = 5; } else if (heading == 3) { heading = 1; } else if (heading == 4) { heading = 6; } else if (heading == 5) { heading = 2; } else if (heading == 6) { heading = 4; } } operation Ball.headingSkiftX1() { if (heading == 1) { heading = 6; } else if (heading == 2) { heading = 5; } else if (heading == 3) { heading = 4; } else if (heading == 4) { heading = 3; } else if (heading == 5) { heading = 2; } else if (heading == 6) { heading = 1; } beregnNext(); } operation Ball.headingSkiftX2() { if (heading == 1) { heading = 4; } else if (heading == 2) { heading = 5; } else if (heading == 3) { heading = 6; } else if (heading == 4) { heading = 1; } else if (heading == 5) { heading = 2; } else if (heading == 6) { heading = 3; } beregnNext(); } operation Ball.move() { y = nextY; x = nextX; beregnNext(); } class Court { attribute width: Integer; attribute height: Integer; attribute refreshDelay: Integer; } attribute Court.width = 400; attribute Court.height = 350; attribute Court.refreshDelay = 5; var court = new Court (); var bat1 = Bat { x: 0, y: 0, width: 5, height: 80, color: yellow}; var bat2 = Bat { x: court.width, y: court.width/2 - bat1.height, width: bat1.width, height: bat1.height, color: blue }; var ball = Ball { x: court.width / 2 - 2, y: court.height / 2 + 25, maxY: court.height, minY:10, heading: 1, step: 0, speed: 7, nextX: court.width / 2 - 2, nextY: court.height / 2 + 25 }; var winInfo = WinInfo { hits: 0, miss: 0, message: "Click Mouse to start" }; trigger on new Ball { beregnNext(); } var myTimer = new Timer(5, new ActionListener() { operation actionPerformed(event:ActionEvent) { if(ball.x + 5 >= court.width) { if(ball.y > bat2.y and ball.y < (bat2.y + bat2.height)) { ball.headingSkiftX1(); if(bat2.color == blue:Color) { bat2.color = red:Color; } else { bat2.color = blue; } winInfo.hits++; winInfo.message = "Hits : {winInfo.hits} Misses : {winInfo.miss}"; } else { ball.x = court.width/5; ball.y = court.height/2; ball.beregnNext(); if(winInfo.miss >= 2) { winInfo.message = "Hits : {winInfo.hits} - GAME OVER - Try Again!"; ((Timer)event.getSource()).stop(); winInfo.miss = 0; } else { winInfo.miss++; winInfo.message = "Hits : {winInfo.hits} Misses : {winInfo.miss}"; try { Thread.sleep(1000); } catch (e:Exception) {} } } } else if(ball.x - 15 < 0) { ball.headingSkiftX1(); } if(ball.heading == 6 or ball.heading == 4) { if(ball.y + bat2.height < court.width) { bat1.x = 0; bat1.y = ball.y; } else { bat1.x = 0; bat1.y = court.width - bat1.height; } } ball.move(); } }); var stoppedByProgram = false; Frame { var: selfFrame width: 419 height: 430 screenx: 100 screeny: 100 title: "JavaFX PingPong" resizable: false disposeOnClose: true var ctrlDlg = Dialog { var: self owner: selfFrame title: "Configure Game Parameters", width: 300, height: 200, modal: true, onClose: operation() { self.visible = false; if (stoppedByProgram) { myTimer.start(); stoppedByProgram = false; } }, content: BorderPanel { center: GridPanel { rows: 3 columns: 2 cells: [Label { text: "Ball Speed" }, Slider { min: 1 max: 25 value: bind ball.speed paintTrack: true paintTicks: true majorTickSpacing: 5 minorTickSpacing: 1 }, Label { text: "System Bat Height" }, Slider { min: 40 max: 120 value: bind bat1.height paintTrack: true paintTicks: true majorTickSpacing: 20 minorTickSpacing: 10 }, Label { text: "User Bat Height" }, Slider { min: 40 max: 120 value: bind bat2.height paintTrack: true paintTicks: true majorTickSpacing: 20 minorTickSpacing: 10 }] } bottom: FlowPanel { content: [Button { text: "OK" mnemonic: ENTER action: operation() { self.visible = false; if (stoppedByProgram) { myTimer.start(); stoppedByProgram = false; } } }, Button { text: "Cancel" mnemonic: ESCAPE action: operation() { self.visible = false; if (stoppedByProgram) { myTimer.start(); stoppedByProgram = false; } } }] } } } content: BorderPanel { center: Canvas { doubleBuffered: true background: green width: bind court.width + 5 height: bind court.height + 5 content: Group { content: [Rect { x: 1 y: 1 width: bind court.width + 2 height: bind court.height + 2 stroke: white strokeWidth: 2 }, Line { x1: bind court.width/2 y1: 0 x2: bind court.width/2 y2: bind court.height stroke: white strokeWidth: 2 }, Ellipse { cx: bind court.width/2 cy: bind court.height/2 radiusX: 50 radiusY: 50 stroke: white strokeWidth: 2 }, Ellipse { cx: bind ball.x cy: bind ball.y radiusX: 10 radiusY: 10 fill: red }, Rect { x: bind bat1.x y: bind bat1.y width: bind bat1.width height: bind bat1.height fill: bind bat1.color }, Rect { x: bind bat2.x y: bind bat2.y width: bind bat2.width height: bind bat2.height fill: bind bat2.color }] } onMouseMoved: operation (e:MouseEvent) { var yy = e.y - bat1.height/2; if(yy > 0 and yy < (court.height - bat2.height)) { bat2.y = yy; } else if(yy < 0) { bat2.y = 0; } else { bat2.y = court.height - bat1.height; } } keyboardAction: KeyboardAction { keyStroke: F1 enabled: true action: operation() { if (myTimer.isRunning()) { stoppedByProgram = true; myTimer.stop(); } ctrlDlg.visible = true; } } onMouseClicked: operation (e:MouseEvent) { ball.beregnNext(); winInfo.hits = 0; winInfo.miss = 0; bat2.x = court.width; bat2.y = court.width/2 - bat2.height; myTimer.start(); winInfo.message = "Hits : {winInfo.hits} Misses : {winInfo.miss}"; } }, bottom: GridPanel { rows: 2 columns: 1 cells: [Label { text: bind winInfo.message font: Font {face: ARIAL, style: [ITALIC, BOLD], size: 15} background: yellow }, Label { text: "Press F1 to customize" font: Font {face: ARIAL, style: [ITALIC, BOLD], size: 15} background: yellow }] } } visible: true }