javaee论坛

普通会员

225648

帖子

345

回复

359

积分

楼主
发表于 2019-11-08 16:39:55 | 查看: 66 | 回复: 2

我接触Qt还不多,想写一个小弹球游戏所以写了这段代码。功能实现因个人水平明显不足以及思维有局限性可能思考的复杂了,代码完成的也比较随意。仅供参考娱乐。同时也产生了一些疑问写在了第四部分。

1.主要功能窗口中组件以及运动效果由QML实现,运动逻辑为JavaScript实现。1)鼠标点击后,小球向鼠标方向运动2)遇到墙壁后反弹

运行效果:

2.逻辑分析虽然在动图看起来是反弹的效果,但在实际代码中,小球则只是反复在做圆心点属性变化的NumberAnimation而已。就是说假如小球初始从A点运动B点。那么当其到达B点时,便会计算出下一个要到达的坐标点C的坐标,小球组件的x,y属性便随之变化为C点坐标,实现运动。依次反复实现运动。(1)鼠标点击后出发运动实际上是小球圆心点坐标的变化,小球圆心点运动的边界为宽和高为窗口高和宽各减去小球半径的矩形,也就是图中红色矩形。首先获取鼠标点击事件出现在1、2、3、4那个区域中,并得到边界矩形定点(getXb_Yb(鼠标x,鼠标y))。其次判断小球本次运动后,落在边界矩形的水平线还是竖直线内,也就是小球在A区域运动还是B区域内,通过比较斜率得到。边界点的x,y坐标有一个是已知的,因此可根据相似三角形原理通过起始点和鼠标点击点计算出本次运动的终点。(getX2_Y2(鼠标x,鼠标y,边界顶点x,边界顶点y))

(2)反弹后出发小球到达前一个运动终点时,立刻再次通过相似三角形原理计算下一个要去的点,并改变圆心的坐标点属性,以此实现运动。反弹后的到达点有可能是在除去反弹边的另外三条边上,因此要先进行判断究竟最后先到哪个边。代码中的想法是,计算假如当小球到达对面边界时,该线上的可变化点(竖直边界y可变化,水平边界x可以变化)是否在边界端点内。但是我忽然意识到具体实现写复杂了,也无伤大雅,也还是相似三角形原理。具体实现想法可以参考下面的图。这样一想好像之前鼠标点击出发的计算也有点复杂。

3)代码文中xm、ym为鼠标坐标,xb、yb为边界顶点,x0、y0以及x2、y3与x3、y3参考上面图中,x1、y1忘了用。另外,代码中一些大于、小于应该修改为大于等于或者小于等于,防止出现一些极端情况。这里不做修改了//主窗口//文中xm、ym为鼠标坐标,xb、yb为边界顶点,x0、y0以及x2、y3与x3、y3参考上面图中,x1、y1忘了用。importQtQuick2.12importQtQuick.Window2.2Window{id:rootvisible:truewidth:640height:480title:qsTr("弹球1.0")propertyvarpiontArray//存储一系列用于计算的坐标点functiongetXb_Yb(Xm,Ym){varXb=[myball.width/2,root.width-myball.width/2]varYb=[myball.width/2,root.height-myball.width/2]if(Xm>myball.circleCenter[0]&&Ym>myball.circleCenter[1]){return[Xb[1],Yb[1]]}elseif(Xm>myball.circleCenter[0]&&Ym<myball.circleCenter[1]){return[Xb[1],Yb[0]]}elseif(Xm<myball.circleCenter[0]&&Ym<myball.circleCenter[1]){return[Xb[0],Yb[0]]}elseif(Xm<myball.circleCenter[0]&&Ym>myball.circleCenter[1]){return[Xb[0],Yb[1]]}}functiongetX2_Y2(Xm,Ym,Xb,Yb){//可能也想复杂了,但计算式是对的vara=(Xm-myball.circleCenter[0])/(Ym-myball.circleCenter[1])//斜率varb=(Xb-myball.circleCenter[0])/(Yb-myball.circleCenter[1])varc=Math.abs(a)>Math.abs(b)?0:1//判别数varX2_Y2console.log(a+"+"+b)if(c===1){varX2=myball.circleCenter[0]-((myball.circleCenter[1]-Yb)/(myball.circleCenter[1]-Ym)*(myball.circleCenter[0]-Xm))X2_Y2=[X2,Yb,myball.circleCenter[0],myball.circleCenter[1]]}else{varY2=myball.circleCenter[1]-((myball.circleCenter[0]-Xb)/(myball.circleCenter[0]-Xm)*(myball.circleCenter[1]-Ym))X2_Y2=[Xb,Y2]}console.log(X2_Y2)return(X2_Y2)}functionyAxisRebound(X0,Y0,X2,Y2,sum){vara=sum===25?615:25varYs2=Y2-((Y2-Y0)/(sum-X0))*(sum-a)//这里想复杂了,可以直接计算的varbb=2*Y2-Ys2varcc=bb>=25&&bb<=455?1:0console.log('------------'+bb)varX3,Y3if(cc===1){Y3=Y2-((Y0-Y2)/(X0-X2)*(a-X2))return[a,Y3,X2,Y2]}elseif(Y2<=Y0&&cc===0){X3=((X0-X2)/(Y0-Y2))*(Y2-25)+X2return[X3,25,X2,Y2]}elseif(Y2>Y0&&cc===0){X3=((X0-X2)/(Y0-Y2))*(Y2-455)+X2return[X3,455,X2,Y2]}}functionxAxisRebound(X0,Y0,X2,Y2,sum){vara=sum===25?455:25varX3,Y3varXs2=X2-(X2-X0)/(sum-Y0)*(sum-a)//这里也想复杂了,可以直接计算的varbb=2*X2-Xs2varcc=bb>=25&&bb<=590?1:0console.log('_____________'+bb)if(cc===1){X3=X2-(a-Y2)*((X2-X0)/(Y2-Y0))return[X3,a,X2,Y2]}elseif(cc===0&&X2<X0){Y3=Y2+((Y2-Y0)/(X2-X0)*(X2-25))return[25,Y3,X2,Y2]}elseif(cc===0&&X2>X0){Y3=Y2+((Y2-Y0)/(X2-X0)*(X2-615))return[615,Y3,X2,Y2]}}Rectangle{id:ccanchors.centerIn:parent;height:root.height-myball.widthwidth:root.width-myball.widthborder.width:0border.color:'black'}MouseArea{id:mousearea;anchors.fill:parent;onClicked:{mousearea.enabled=falsevarXb=getXb_Yb(mouse.x,mouse.y)[0]varYb=getXb_Yb(mouse.x,mouse.y)[1]varX2=getX2_Y2(mouse.x,mouse.y,Xb,Yb)[0]varY2=getX2_Y2(mouse.x,mouse.y,Xb,Yb)[1]piontArray=[myball.circleCenter[0],myball.circleCenter[1],X2,Y2]//刷新存储的坐标myball.circleCenter=[X2,Y2]}}MyBall{id:myballwidth:50circleCenter:[320,240]//root.height-width/2+1]onX0Changed:{if(myball.x0===25||myball.x0===615){console.log("o9k");varX3_Y3=yAxisRebound(piontArray[0],piontArray[1],piontArray[2],piontArray[3],myball.x0)piontArray=[X3_Y3[2],X3_Y3[3],X3_Y3[0],X3_Y3[1]]//刷新存储的坐标myball.circleCenter=[X3_Y3[0],X3_Y3[1]]console.log(X3_Y3[0],X3_Y3[1])}}onY0Changed:{if(myball.y0===25||myball.y0===455){varX3_Y3=xAxisRebound(piontArray[0],piontArray[1],piontArray[2],piontArray[3],myball.y0)piontArray=[X3_Y3[2],X3_Y3[3],X3_Y3[0],X3_Y3[1]]//刷新存储的坐标myball.circleCenter=[X3_Y3[0],X3_Y3[1]]console.log("xRebound")}}}}小球组件的代码importQtQuick2.12Rectangle{propertyvarcircleCenterpropertyvarborderConditionpropertyrealdistance:200propertyrealx0:x+25propertyrealy0:y+25signalborderid:circlex:circleCenter[0]-width/2y:circleCenter[1]-height/2height:widthradius:height/2border{color:"black";width:3}color:"red"Behavioronx{NumberAnimation{id:xBehavior;duration:distance*5;}//动画完成时间可以利用距离完成匀速运动,这里没改}Behaviorony{NumberAnimation{id:yBehavior;duration:distance*5;}}}4)一些疑问之前更多的编程是单片机的面向过程编程,比如我若是想实现一个小车在封闭空间内往复运动,应该会是这样的思路:voidmain(.......while(传感器没输入){轮子=转;}if(传感器A=1){旋转(应旋转角度);}if(...)..),单片机循环扫描即可,以此来实现。但我没有想出这种逻辑是不是在QML这类语言中也能实现,所以就才用了计算终点,利用动画运动的方式。

普通会员

0

帖子

319

回复

322

积分
沙发
发表于 2023-12-18 07:56:18

还是很厉害的

普通会员

10

帖子

303

回复

329

积分
板凳
发表于 2024-04-26 17:38:04

还是很厉害的

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017