Unsolved Offer me a good QML exercise
-
@J.Hilk
Pong is much cooler but how to play such a two-player game on a smartphone? We need joysticks. So I go for the one-player version of the game. -
@tomy ok,
but fyi, Most, if not all, smartphones have a multi touch screen, So it should be possible to play with 2 players.alternatively, this could also be a good option for you to get into networking, to play on 2 phones via bluetooth or wlan. ;-)
-
alternatively, this could also be a good option for you to get into networking, to play on 2 phones via bluetooth or wlan. ;-)
I guess we have two parts, the first is designing the stuff and the last part is networking (via wlan).
I think it's too advanced for me, but I like it and go for that. -
I started by a project named PingPong! I've reached that point up to now:
main.qml
:import QtQuick 2.8 import QtQuick.Window 2.2 Window { visible: true width: 800 height: 600 title: qsTr("The Ping Pong game") Rectangle { id: root width: 700; height: 500 border.width: 10 border.color: "black" color: "royalblue" property int duration: 1000 Racket { x: 630; y: 100 color: "red" } Racket { x: 50; y: 100 color: "black" } Ball { id: ball x: root.width/2 - 50 y: root.height/2 } Rectangle { x: root.width/2 y: 10 width: 10 height: root.height - 20 color: "white" } } }
Ball.qml
:import QtQuick 2.8 Rectangle { width: 20; height: 20 x: 250; y: 250 color: "white" radius: width/2 }
Racket.qml
:import QtQuick 2.8 Rectangle { id: root width: 15; height: 50 x: 400; y: 100 color: "red" MouseArea { anchors.fill: parent drag.target: root drag.axis: Drag.YAxis drag.minimumY: 10 drag.maximumY: 440 } }
I have this up to now:
The rackets work good with the mouse button but will they work as well with touching on smartphones?
Now what I need is animating the ball using Easing.Linear. The ball also should start animating when the program starts and recognizes the rackets and the top and down part of the table to reflect.
what should I read for these please? -
@tomy
Hiho,Internaly Qt does not differ between mouse clicks and touch events, so if it works fine with the mouse, than it should work fine on the phone display.
I don't think there is much to read upon for you, you should be able to do that "collision" with what you know.
E.g
You monitor the x-position of your ball. If it hits the x-position of one of the rackets, check if the y-positions of ball and racket overlap.
If yes : Stop old animation of ball and start new one if not, let animation finish and change score counter. -
For this point I changed the
main.qml
to this:import QtQuick 2.8 import QtQuick.Window 2.2 Window { visible: true width: 800 height: 600 title: qsTr("The Ping Pong game") Rectangle { id: root width: 700; height: 500 border.width: 10 border.color: "black" color: "royalblue" property int duration: 1000 property real xPos: root.width property real yPos: Math.random() Racket { id: redRacket x: 630; y: 100 color: "red" } Racket { id: blackRacket x: 50; y: 100 color: "black" } Ball { id: ball x: root.width/2 - 50 y: root.height/2 } Column { spacing: 3 x: root.width/2 y: 10 Repeater { model: 21 delegate: Rectangle { width: 5 height: 20 color: "white" } } } ParallelAnimation { id: anim1 NumberAnimation { target: ball properties: "x" to: root.xPos duration: root.duration easing.type: Easing.Linear } NumberAnimation { target: ball properties: "y" to: root.yPos duration: root.duration easing.type: Easing.Linear } } function nextPos() { if(ball.x == redRacket.x && ball.y == redRacket.y) { ParallelAnimation { id: anim2 NumberAnimation { target: ball properties: "x" to: -root.xPos duration: root.duration easing.type: Easing.Linear } NumberAnimation { target: ball properties: "y" to: root.yPos duration: root.duration easing.type: Easing.Linear } } } } MouseArea { anchors.fill: ball onClicked: { anim1.restart(); anim2.restart() } } } }
The net is better and also I tried to make the ball animate on two opposite directions. But I get these errors:
qrc:/main.qml:76 Expected token ,'
qrc:/main.qml:78 Expected token `}'By the way, the Math.random() function seems not to work!
-
@tomy
first of let me tell you, as a person with slight ocd-issues, the fact that your indenting is off, is driving me nuts x)Anyway:
you define a function
nextPos()
and insinde the function-body you try to define a ParallelAnimation item and NumberAnimation items. That can't work.only calculate assign values&properties in functions! Not new items.
In C++ you would, kind of, get way with it, but defenitly not in QML :-) -
@J.Hilk
Sorry, I don't know if there is an option that offer automatic indenting on Qt Creator. Do you mean the code looks ugly? :-)Anyway,
The functionsMath.random()
andnextPos()
andif-condition
are fixed:import QtQuick 2.8 import QtQuick.Window 2.2 Window { visible: true width: 800 height: 600 title: qsTr("The Ping Pong game") Rectangle { id: root width: 700; height: 500 border.width: 10 border.color: "black" color: "royalblue" property int duration: 1000 property real xPos: root.width property real yPos: Math.random() * root.height Racket { id: redRacket x: 630; y: 100 color: "red" } Racket { id: blackRacket x: 50; y: 100 color: "black" } Ball { id: ball x: root.width/2 - 50 y: root.height/2 } Column { spacing: 3 x: root.width/2 y: 10 Repeater { model: 21 delegate: Rectangle { width: 5 height: 20 color: "white" } } } ParallelAnimation { id: anim1 NumberAnimation { target: ball properties: "x" to: root.xPos duration: root.duration easing.type: Easing.Linear } NumberAnimation { target: ball properties: "y" to: root.yPos duration: root.duration easing.type: Easing.Linear } } ParallelAnimation { id: anim2 NumberAnimation { target: ball properties: "x" to: -root.xPos duration: root.duration easing.type: Easing.Linear } NumberAnimation { target: ball properties: "y" to: root.yPos duration: root.duration easing.type: Easing.Linear } } function nextPos() { if(ball.x >= redRacket.x && ball.x <= redRacket.x + redRacket.height) { anim1.stop(); anim2.start(); } } MouseArea { anchors.fill: ball onClicked: { anim1.start(); root.nextPos(); } } } }
The x position of the ball is for when it hasn't been animated yet so it won't work in the condition. I need something like:
if (hit(ball,redRacket))
The second is that in:
anim1.stop(); anim2.start();
anim2.start()
doesn't letanim1.start()
work! -
@tomy Hiho
So, I took a look at your code. I'm not quite sure why it's not working like you want it to.
My guess would be, its quite difficult to click upon the ball when its in the window when its in the Racket.So I simpliefied the situation a bit
I added 2 Properties and a timer to help:
The timer was needed in my testing, otherwise it would change animation anproperty bool toTheRight: true property bool delay: false Timer{ id: delayTimer interval: 500; running: false; repeat: false onTriggered: delay = false } onToTheRightChanged: { delay = true delayTimer.start() }
nextPos() was slighly changed, it currently only checks if the ball is past a line:
function nextPos() { if(!delay){ if(ball.x + ball.width >= redRacket.x || ball.x <= blackRacket.x + blackRacket.width){ toRight = !toRight console.log("Ball hits a racket") if(anim1.running) anim1.stop() else anim1.start() if(anim2.running) anim2.stop() else anim2.start() } } }
The Ball item calls nextPos():
Ball { id: ball x: root.width/2 - 50 y: root.height/2 onXChanged: nextPos() } ... MouseArea { anchors.fill: ball onClicked: { anim1.start(); /*root.nextPos();*/} }
This works fine for me, its results in the ball pinging from one wall to the other.
Next step would be to add the player input conditions.hope this helps.
-
@J.Hilk
Thank you.
Timer was very useful. I wrote this:import QtQuick 2.8 import QtQuick.Window 2.2 Window { visible: true width: 800 height: 600 title: qsTr("The Ping Pong game") Rectangle { id: table width: 700; height: 500 border.width: 10 border.color: "black" color: "royalblue" Racket { id: redRacket x: 630; y: 100 color: "red" } Racket { id: blackRacket x: 50; y: 100 color: "black" } Ball { id: ball x: table.width/2 - 50 y: table.height/2 property double ran: Math.random() + 0.5 property double xincrement: ran property double yincrement: ran } Column { spacing: 3 x: table.width/2 y: 10 Repeater { model: 21 delegate: Rectangle { width: 5 height: 20 color: "white" } } } Timer { interval: 5; repeat: true; running: true onTriggered: { ball.x = ball.x + (ball.xincrement * 2.0); ball.y = ball.y + (ball.yincrement * 2.0); if((ball.x + ball.width >= redRacket.x) && ((ball.y + ball.height >= redRacket.y) && (ball.y + ball.height <= redRacket.y + redRacket.height))) ball.xincrement *= (-1); if((ball.x - ball.width <= blackRacket.x) && ((ball.y + ball.height >= blackRacket.y) && (ball.y + ball.height <= blackRacket.y + blackRacket.height))) ball.xincrement *= (-1); if(ball.y <= 0 || ball.y + ball.height >= table.height) ball.yincrement *= (-1); } } } }
It works fine but the players can't shoot the ball towards a target they want! The rackets are this way only for defending. I need to alter the code so that when the racket has speed upward or downward hitting the ball, the ball goes and gets acceleration on that direction. The real game has that feature.
How can I do that, please?After that I'll go for other missing parts for the game.
-
@tomy
well, first you'll need to somehow monitor if the racket moved up or down as its last movement.I don't see how in the code examples you posted how you manage the "Racket-Movement" .
but it doesn't matter much, it can be a property of the Racket Item
#untested Stuff
e.g:Rectangle { id: redRacket x: 630; y: 100 color: "red" property int oldY: 100 property bool upMovement: false onYChanged:{ upMovement = y -oldY < 0 ? true : false oldY = y } width: 50 height: 100 }
and when the Ball hits the racket you decrease the duration, and depending on the up or down movement you change the angle
function onCollisionWithRacket(){ root.duration = root.duration -10 if(redRacket.upMovement){ //Angle to the Top }else{ //Angle to the bottom } }
-
@J.Hilk
Thanks.
I tried to make the work done and here is the code.
I don't use the prior versions of the code (above) but this one.Ball.qml
andRacket.qml
are as before butmain.qml
is completely as below.As you see I haven't used a function and I don't know if it's needed or not.
If possible please run that code to see its function. I don't think it's flawless.
The code also to me is very messy. If it can make the work done using little changes, what to do for removing the problems from that please?import QtQuick 2.8 import QtQuick.Window 2.2 Window { visible: true width: 800 height: 600 title: qsTr("The PingPong Game") Rectangle { id: table width: 700; height: 500 border.width: 10 border.color: "black" color: "royalblue" Racket { id: redRacket x: 630; y: 100 color: "red" property int rOldy: y property bool rYmovement: false onYChanged: { rYmovement = y - rOldy < 0 ? true : false rOldy = y } } Racket { id: blackRacket x: 50; y: 100 color: "black" property int bOldy: y property bool bYmovement: false onYChanged: { bYmovement = y - bOldy < 0 ? true : false bOldy = y } } Ball { id: ball x: table.width/2 - 50 y: table.height/2 property double ran: Math.random() + 0.5 property double xincrement: ran property double yincrement: ran } Column { spacing: 3 x: table.width/2 y: 10 Repeater { model: 21 delegate: Rectangle { width: 5 height: 20 color: "white" } } } Timer { interval: 15; repeat: true; running: true onTriggered: { ball.x = ball.x + (ball.xincrement * 2.0); ball.y = ball.y + (ball.yincrement * 2.0); if((ball.x + ball.width >= redRacket.x) && ((ball.y + ball.height >= redRacket.y) && (ball.y + ball.height <= redRacket.y + redRacket.height))) if(redRacket.rYmovement) { ball.yincrement *= -1 ball.xincrement *= -1 redRacket.rYmovement = false } else ball.xincrement *= -1 if((ball.x - ball.width <= blackRacket.x) && ((ball.y + ball.height >= blackRacket.y) && (ball.y + ball.height <= blackRacket.y + blackRacket.height))) if(blackRacket.bYmovement) { ball.yincrement *= -1 ball.xincrement *= -1 blackRacket.bYmovement = false } else ball.xincrement *= -1 if(ball.y <= 0 || ball.y + ball.height >= table.height) ball.yincrement *= -1 } } } }
-
to make it a bit cleaner, if you for example moved some stuff to the Ball and Racket qml-files
//Racket import QtQuick 2.8 Rectangle { id: root width: 15; height: 50 x: 400; y: 100 color: "red" property int oldY: y property bool yMovement: false onYChanged: { yMovement = y - oldY < 0 ? true : false oldY = y } MouseArea { anchors.fill: parent drag.target: root drag.axis: Drag.YAxis drag.minimumY: 10 drag.maximumY: 440 } }
//Ball.qml import QtQuick 2.8 Rectangle { width: 20; height: 20 x: 250; y: 250 color: "white" radius: width/2 property double ran: Math.random() + 0.5 property double xincrement: ran property double yincrement: ran }
Besides that I don't see what the problem is, theres at least 1 bug I run into whilst playing, x) but thats part of coding.
If you thinks the animation is a but stuttery thats to be expected, you replaced a propertyanimation with a Timer and x/y changes.
I believe, PropertyAnimation does some internal stuff to make the animation as smooth as possible, a change each refresh frame e.g. Where as with a timer aproeach you are fixed to 5 ms updates and in that you only increase the distance the ball is moved. That gonna look like jumps eventually ;-)
-
I replaced the PropertyAnimation with Timer because I didn't know how to achieve what I have now without Timer but with PropertyAnimation.
The Timer works fine with smoothness but in this example I'd changed the interval from 2 to 15 to slow the movement of the ball for better testing.The game has defects even in this point unfortunately. And it's the feature of targeting.
Theif(redRacket.rYmovement)
conditions code don't work as expected. I should think over them so that they work as needed.
But a question here, does the y coordinate change relate to the "last" movement of the racket before the ball hits it? -
I changed the timer stuff a bit, to make it more readable, what happens
Timer { interval: 15; repeat: true; running: true function hitsRightRacket(){ if(ball.x +ball.width >= redRacket.x && ball.x < redRacket.x + redRacket.width){ if(ball.y >= redRacket.y && ball.y <= redRacket.y+redRacket.height) return true } return false } function hitsLeftRacket(){ if(ball.x +ball.width >= blackRacket.x && ball.x < blackRacket.x + blackRacket.width){ if(ball.y >= blackRacket.y && ball.y <= blackRacket.y+blackRacket.height) return true } return false } function hitsRightWall(){ if(ball.x +ball.width >= table.width) return true else return false } function hitsLeftWall(){ if(ball.x <= 0) return true else return false } function hitsUpperOrLowerWall(){ if(ball.y <= 0 || ball.y + ball.height >= table.height) return true return false } property bool lastHitLeft: false property bool lastHitRight: false onTriggered: { if(hitsRightWall()){ console.log("Point Left Side") running = false }else if(hitsLeftWall()){ console.log("Point Right Side") running = false }else if(hitsLeftRacket() && !lastHitLeft){ console.log("Hits Black Racket",blackRacket.yMovement) lastHitLeft = true lastHitRight = false if(blackRacket.yMovement){ ball.yincrement *= -1 ball.xincrement *= -1 }else ball.xincrement *= -1 }else if(hitsRightRacket() && !lastHitRight){ console.log("Hits Red Racket",redRacket.yMovement) lastHitLeft = false lastHitRight = true if(redRacket.yMovement) { ball.yincrement *= -1 ball.xincrement *= -1 } else ball.xincrement *= -1 }else if(hitsUpperOrLowerWall()) ball.yincrement *= -1 //Move Ball ball.x = ball.x + (ball.xincrement * 2.0); ball.y = ball.y + (ball.yincrement * 2.0); } }
This showed me that you'll need a better case handleing for ball movement and racket movement,
- ball moves towards y = 0 and Racket moves towards y = 0
- ball moves towards y = 0 and Racket moves towards y = table height
- ball moves towards y = table and Racket moves towards y = 0
- ball moves towards y = table Racket moves towards y = table height
currently you're only checking in what direction the racket moved,
-
@J.Hilk
Hi,
Thank you for your assistance.If we divide the task into part
I
andII
, the first part I think is almost done! Please take a look at the code below and if possible please run the program on your system. It works fine for me.In part
I
, I need two extra components I think: one, a series of buttons for starting, resuming and finishing the game when it's not over yet. And second, some sound for goals and when a player wins the game.
If we can complete partI
, I assume partII
will be about networking! :)Ball.qml
:import QtQuick 2.9 Rectangle { width: 12; height: 12 x: 250; y: 250 color: "white" radius: width/2 property double ran: Math.random() + 0.5 property double xincrement: ran property double yincrement: ran }
Counter.qml
:import QtQuick 2.9 Rectangle { width: 40; height: 50 color: "lightskyblue" property int count: 0 Text { id: text anchors.centerIn: parent text: count.toString() color: "gray" font.bold: true font.pixelSize: 30 } }
Light.qml
:import QtQuick 2.9 Rectangle { width: 50; height: 50 border.width: 5 border.color: "silver" radius: width/2 property bool start: false }
Racket.qml
:import QtQuick 2.9 Rectangle { id: root width: 12; height: 40 property int oldY: y property bool yUwards: false property bool yDwards: false onYChanged: { if(y > oldY) yDwards = true else if (y < oldY) yUwards = true oldY = y } MouseArea { anchors.fill: parent drag.target: root drag.axis: Drag.YAxis drag.minimumY: table.y - 20 drag.maximumY: table.y + table.height - 60 } }
WinBox.qml
:import QtQuick 2.9 Text { width: 50; height: 50 text: "WINNER" color: "royalblue" font.bold: true font.pixelSize: 40 visible: false }
main.qml
:import QtQuick 2.9 import QtQuick.Window 2.2 Window { visible: true width: 820 height: 620 title: qsTr("The PingPong Game") color: "gray" Rectangle { x: 10; y: 10 width: 800; height: 500 color: "white" } Rectangle { id: table x: 20; y: 20 width: 780; height: 480 color: "royalblue" property int count: 1 property bool turn: false property bool lightState: false Racket { id: redRacket x: table.width - 30; y: 100 color: "red" } Racket { id: blackRacket x: table.x; y: 100 color: "black" } Ball { id: ball x: table.width/2 y: table.height/2 } Column { spacing: 3 x: table.width/2 Repeater { model: 21 delegate: Rectangle { width: 5 height: 20 color: "white" } } } Counter { id: rightCounter x: table.width / 2 + 90 y: 50 } Counter { id: leftCounter x: table.width / 4 + 70 y: 50 } Light { id: rightLight x: table.width/2 + 80 y: table.height + 20 color: "silver" } Light { id: leftLight x: table.width/2 - 120 y: table.height + 20 color: "lime" } WinBox { id: rightWin x: table.width/2 + 160 y: table.height + 40 } WinBox { id: leftWin x: table.width/2 - 350 y: table.height + 40 } Timer { interval: 40; repeat: true; running: true onTriggered: { redRacket.yUwards = false redRacket.yDwards = false blackRacket.yUwards = false blackRacket.yDwards = false } } Timer { id: out_timer interval: 1; repeat: false; running: false function lightChange() { if (table.lightState) { rightLight.color = "silver" leftLight.color= "lime" } else { rightLight.color = "lime" leftLight.color= "silver" } table.lightState = !table.lightState } onTriggered: { ball.xincrement = Math.random() + 0.5 ball.yincrement = Math.random() + 0.5 if( table.count % 5 == 0) { table.turn = !table.turn lightChange() } if(table.turn) ball.xincrement *= -1 ball.x = table.width/2 ball.y = table.height/2 if (ball.yincrement > 1.1) ball.yincrement *= -1 in_timer.restart() table.count++ } } Timer { id: in_timer interval: duration; repeat: true; running: true property int duration: 2 function hitsRightWall() { if (ball.x + ball.width >= table.width) return true else return false } function hitsLeftWall() { if(ball.x <= 0) return true else return false } property bool lastHitLeft: false property bool lastHitRight: false onTriggered: { if(hitsRightWall()) { in_timer.stop() leftCounter.count++ out_timer.interval = 2000 out_timer.running = true } else if(hitsLeftWall()) { in_timer.stop() rightCounter.count++ out_timer.interval = 2000 out_timer.running = true } ball.x = ball.x + (ball.xincrement * 2.0); ball.y = ball.y + (ball.yincrement * 2.0); if ((ball.x + ball.width >= redRacket.x && ball.x < redRacket.x + redRacket.width / 3) && (ball.y + ball.height >= redRacket.y - 10 && ball.y <= redRacket.y + redRacket.height)) { if(redRacket.yUwards) { if(ball.yincrement == 0) ball.yincrement = -ball.ran else if(ball.yincrement > 0) ball.yincrement *= -1 interval = duration/2 } else if (redRacket.yDwards) { if(ball.yincrement == 0) ball.yincrement = ball.ran else if(ball.yincrement < 0) ball.yincrement *= -1 interval = duration/2 } else { ball.yincrement = 0 interval = duration } ball.xincrement *= -1 } if ((ball.x + ball.width >= blackRacket.x && ball.x < blackRacket.x + blackRacket.width) && (ball.y + ball.height >= blackRacket.y && ball.y <= blackRacket.y + blackRacket.height)) { if(blackRacket.yUwards) { if(ball.yincrement == 0) ball.yincrement = -ball.ran else if(ball.yincrement > 0) ball.yincrement *= -1 interval = duration/2 } else if (blackRacket.yDwards) { if(ball.yincrement == 0) ball.yincrement = ball.ran else if(ball.yincrement < 0) ball.yincrement *= -1 interval = duration/2 } else { ball.yincrement = 0 interval = duration } ball.xincrement *= -1 } if(ball.x <= 0 || ball.x + ball.width >= table.width) ball.xincrement *= (-1); if(ball.y <= 0 || ball.y + ball.height >= table.height) ball.yincrement *= -1 if(rightCounter.count + leftCounter.count == 21) { in_timer.stop() if(rightCounter.count > leftCounter.count) rightWin.visible = true else if (rightCounter.count < leftCounter.count) leftWin.visible = true else { rightWin.visible = true leftWin.visible = true } } } } } }
-
Looks great! You're defenitly on the right track.
However I have a bug to report. I managed to
catch
the ball in the racket. That's the reasdon why I introtuced the 2 propertieslastHitLeft
andlastHitRight
in my previous post. You still have them in your code, but they are not used.
-
@J.Hilk
Hi, thanks.Well, I laid those factors and ran the code. Unfortunately it made the issue more prominent! The ball passes through the ball obliquely.
So I think I must return back to the version without them and the issue is subtle! It happens when a racket tries to hit the ball from the top/down moving downwards/upwards and the ball gets stuck in the upper/lower edge of the racket. I think I should work on this.
Previously I was thinking of making the racket thinner to prevent this bug. But I try to find a more logical way.
-
Hi,
For a while I was trying to use contains(point p), mapFromItem(...) or mapToItem(...). But unfortunately, no success! So I got back to the prior method, which was using the X and Y coordinates as follows.
Please run it on your system. It works fine for me. The bug is also solved.
But there's another bug!- Moving the racket when playing the game on the Desktop kit (Windows) doesn't affect the speed of ball's movement but when run on an Android device, moving the racket affects the speed of ball's movement as though their movements have been tied together.
I also tried to manipulate the
MouseArea
in theRacket.qml
to cope with that, but no change in the result! :(Please check it and express your idea how to solve that issue.
QML files
Ball
,Counter
,Light
andWinbox
are as before.Racket.qml
:import QtQuick 2.9 Rectangle { id: root width: 15; height: 65 property int oldY: y property bool yUwards: false property bool yDwards: false onYChanged: { if(y > oldY) yDwards = true else if (y < oldY) yUwards = true oldY = y } MouseArea { anchors.fill: parent anchors.margins: -root.height drag.target: root focus: true hoverEnabled: true pressAndHoldInterval: 0 drag.axis: Drag.YAxis drag.minimumY: table.y drag.maximumY: table.height - root.height - 10 } }
main.qml
:import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.1 Window { id: window visibility: Window.Maximized title: qsTr("The PingPong Game - A QML Game") color: "gray" Rectangle { id: table width: window.width / 1.15; height: window.height / 1.15 x: window.x + 100; y: 10; border.width: 10 border.color: "white" color: "royalblue" property int count: 1 property bool turn: false property bool lightState: false property double step: 3.0 property int duration: 4 Racket { id: blackRacket anchors.left: table.left anchors.leftMargin: width * 2 y: height color: "black" } Racket { id: redRacket anchors.right: table.right anchors.rightMargin: width * 2 y: height color: "red" } Ball { id: ball x: table.width/2 y: table.height/2 } Column { spacing: 3 anchors.centerIn: table anchors.top: table.top Repeater { model: table.height/(blackRacket.height / 2 + 3) delegate: Rectangle { width: 5 height: blackRacket.height / 2 color: "white" } } } Counter { id: leftCounter x: table.width / 2 - height - 100 y: 50 } Counter { id: rightCounter x: table.width / 2 + 100 y: 50 } Light { id: leftLight x: table.width/2 - 280 y: table.height + 10 color: "lime" } Light { id: rightLight x: table.width/2 + 220 y: table.height + 10 color: "silver" } WinBox { id: rightWin x: table.width/2 + 380 y: table.height + 10 } WinBox { id: leftWin x: table.x + 40 y: table.height + 10 } Button { x: table.width/2 - 45 y: table.height + 10 contentItem: Text { id: st_tx horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("START") font.bold: true font.pixelSize: 20 color: "green" } background: Rectangle { implicitHeight: 60 implicitWidth: 100 color: "lightGrey" border.width: 8 border.color: "lightBlue" radius: 20 } onClicked: table.startGame() } Button { x: table.width/2 - 150 y: table.height + 10 contentItem: Text { id: pu_tx horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("PAUSE") font.bold: true font.pixelSize: 20 color: "green" } background: Rectangle { id: pu_rec implicitHeight: 60 implicitWidth: 100 color: "lightGrey" border.width: 8 border.color: "lightBlue" radius: 20 } onClicked: table.pauseGame() } Button { x: table.width/2 + 60 y: table.height + 10 contentItem: Text { id: sp_tx horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text: qsTr("STOP") font.bold: true font.pixelSize: 20 color: "green" } background: Rectangle { implicitHeight: 60 implicitWidth: 100 color: "lightGrey" border.width: 8 border.color: "lightBlue" radius: 20 } onClicked: table.stopGame() } Text { x: window.x; y: table.height + 50 color: "white" text: "Ver: 1.1" font.family: "Helvetica" font.pointSize: 15 } Text { x: table.width - 200; y: table.height + 50 color: "white" text: " Programmed By S.R. Abbasi (Tomy)" font.family: "Helvetica" font.pointSize: 10 } function startGame() { st_tx.text = qsTr("START") if (leftWin.visible) leftWin.visible = false if (rightWin.visible) rightWin.visible = false in_timer.restart() } function pauseGame() { st_tx.text = qsTr("RESUME") in_timer.running = false } function stopGame() { st_tx.text = qsTr("START") in_timer.running = false rightCounter.count = 0 leftCounter.count = 0 ball.x = table.width/2 ball.y = table.height/2 table.count = 1 table.turn = false rightLight.color = "silver" leftLight.color = "lime" if(ball.xincrement < 0 ) ball.xincrement *= -1 } Timer { interval: 40; repeat: true; running: true onTriggered: { redRacket.yUwards = false redRacket.yDwards = false blackRacket.yUwards = false blackRacket.yDwards = false } } Timer { id: out_timer interval: 1; repeat: false; running: false function lightChange() { if (table.lightState) { rightLight.color = "silver" leftLight.color= "lime" } else { rightLight.color = "lime" leftLight.color= "silver" } table.lightState = !table.lightState } onTriggered: { ball.xincrement = Math.random() + 0.5 ball.yincrement = Math.random() + 0.5 if (table.count % 5 == 0) { table.turn = !table.turn lightChange() } if (table.turn) ball.xincrement *= -1 ball.x = table.width/2 ball.y = table.height/2 if (ball.yincrement > 1.1) ball.yincrement *= -1 in_timer.restart() table.count++ } } Timer { id: right_return_timer interval: 1; repeat: true; running: false onTriggered: { ball.x = ball.x + (ball.xincrement * table.step) ball.y = ball.y + (ball.yincrement * table.step) if(ball.x + ball.width < redRacket.x) { running = false in_timer.running = true } } } Timer { id: left_return_timer interval: 1; repeat: true; running: false onTriggered: { ball.x = ball.x + (ball.xincrement * table.step) ball.y = ball.y + (ball.yincrement * table.step) if(ball.x > blackRacket.x + blackRacket.width) { running = false in_timer.running = true } } } Timer { id: in_timer interval: table.duration; repeat: true; running: false function hitsRightRacket() { if ((ball.x + ball.width >= redRacket.x && ball.x <= redRacket.x + redRacket.width) && (ball.y + ball.height >= redRacket.y && ball.y <= redRacket.y + redRacket.height)) return true return false } function hitsLeftRacket() { if ((ball.x + ball.width >= blackRacket.x && ball.x < blackRacket.x + blackRacket.width) && (ball.y + ball.height >= blackRacket.y && ball.y <= blackRacket.y + blackRacket.height)) return true return false } function hitsUpperOrLowerWall(){ if (ball.y <= 0 || ball.y + ball.height >= table.height) return true return false } function hitsRightWall() { if (ball.x + ball.width >= table.width) return true else return false } function hitsLeftWall() { if (ball.x <= 0) return true else return false } onTriggered: { if (hitsRightWall()) { in_timer.stop() leftCounter.count++ out_timer.interval = 2000 out_timer.running = true } else if (hitsLeftWall()) { in_timer.stop() rightCounter.count++ out_timer.interval = 2000 out_timer.running = true } else if (hitsRightRacket()) { if (redRacket.yUwards) { if (ball.yincrement == 0) ball.yincrement = -ball.ran else if (ball.yincrement > 0) ball.yincrement *= -1 interval = (table.duration/4) } else if (redRacket.yDwards) { if (ball.yincrement == 0) ball.yincrement = ball.ran else if (ball.yincrement < 0) ball.yincrement *= -1 interval = (table.duration/4) } else { ball.yincrement = 0 interval = (table.duration/2) } ball.xincrement *= -1 running = false right_return_timer.running = true } else if (hitsLeftRacket()) { if(blackRacket.yUwards) { if (ball.yincrement == 0) ball.yincrement = -ball.ran else if (ball.yincrement > 0) ball.yincrement *= -1 interval = (table.duration/4) } else if (blackRacket.yDwards) { if (ball.yincrement == 0) ball.yincrement = ball.ran else if (ball.yincrement < 0) ball.yincrement *= -1 interval = (table.duration/4) } else { ball.yincrement = 0 interval = (table.duration/2) } ball.xincrement *= -1 running = false left_return_timer.running = true } else if (hitsUpperOrLowerWall()) ball.yincrement *= -1 // Move Ball ball.x = ball.x + (ball.xincrement * table.step); ball.y = ball.y + (ball.yincrement * table.step); if(rightCounter.count + leftCounter.count == 21) { in_timer.stop() if (rightCounter.count > leftCounter.count) rightWin.visible = true else leftWin.visible = true } } } } }
-
Hi @tomy , sorry for the late response.
I had a lengthly break, sickness and holiday - thankfully not overlapping. But I'm back now and will take a look later today. I actually managed not to touch my laptop during that time, that was difficult I'll tell ya.
Any progress in the last 23 days ?
Greetings.