永远的GitHub地址: https://github.com/JianBiHua/go_360_safe
这节浪费了我很长时间,主要是遇到了个大坑,找了好久,一直以为是QT库对UI的兼容不好,无法使用paint,折腾折腾,今天终于找到问题了,所以才发.
先看效果图,养养眼
我们的波浪球是用Paint画的,共有三种形态,三种颜色。自由组合就是9种,哈哈,开玩笑。
状态一,带图片的球球
状态二,有波浪的球球
状态三, 有气泡的球球
原理如下, 美工水平有限凑合看吧.
先看上图
- 粉丝那个是后面的那个波浪
- 红色的是前面的波浪
- 圆是遮罩层,
最后合并后的效果如下.
当粉丝和红色向一个方向移动时,就会产生波浪的效果了.
核心代码:
// 画波浪
// isHalf 是否是画半透明波浪,半透明则为背景, 实体色为前面.
func (b *WaveBallWidget) drawWave(isHalf bool) {
b.painter.Save()
// 设置颜色。
b.painter.SetPen3(core.Qt__NoPen)
b.painter.SetBrush(gui.NewQBrush10(b.getLGColor(isHalf)))
sx := float64(b.X() + b.pX)
sy := float64(b.Y() + b.pY)
// 单元宽度
u := float64(b.Height() / 2)
// 根据进度,设置高度
y := float64(2 * u * float64((1 - float64(b.progress)/100.0)))
// 波形高度
waveH := 15.0
offset := float64(b.waveOffset)
//
path := gui.NewQPainterPath()
path.MoveTo2(offset+sx, sy+y)
if isHalf {
path.QuadTo2(offset+u/2+sx, sy+waveH+y, offset+u+sx, sy+y)
path.QuadTo2(offset+u/2+u+sx, sy-waveH+y, offset+2*u+sx, sy+y)
path.QuadTo2(offset+u/2+u*2+sx, sy+waveH+y, offset+u*3+sx, sy+y)
path.QuadTo2(offset+u/2+u*3+sx, sy-waveH+y, offset+4*u+sx, sy+y)
path.QuadTo2(offset+u/2+u*4+sx, sy+waveH+y, offset+5*u+sx, sy+y)
} else {
path.QuadTo2(offset+u/2+sx, sy-waveH+y, offset+u+sx, sy+y)
path.QuadTo2(offset+u/2+u+sx, sy+waveH+y, offset+2*u+sx, sy+y)
path.QuadTo2(offset+u/2+u*2+sx, sy-waveH+y, offset+u*3+sx, sy+y)
path.QuadTo2(offset+u/2+u*3+sx, sy+waveH+y, offset+4*u+sx, sy+y)
path.QuadTo2(offset+u/2+u*4+sx, sy-waveH+y, offset+5*u+sx, sy+y)
}
path.LineTo2(offset+5*u+sx, 2*u+sy+y)
path.LineTo2(sx, 2*u+sy+y)
path.LineTo2(sx, sy+y)
path2 := gui.NewQPainterPath()
path2.AddEllipse2(6+sx, 6+sy, float64(b.Width()-12), float64(b.Height()-12))
b.painter.SetClipPath(path, core.Qt__ReplaceClip)
b.painter.DrawPath(path2)
b.painter.Restore()
}
波浪移动代码如下:
实际上就是启动了一个时间计时器, 修改两个层当前的位置,并刷新.
波浪自然就向前滚动了;
为了实现无限滚动,所以画的是两倍于遮罩层的大小, 当滚动到合适位置,将两层拉到初始的相应位置.
// 启动波浪
func (b *WaveBallWidget) startWave() {
b.waveTicker = time.NewTicker(50 * time.Millisecond)
go func() {
for {
select {
case <-b.waveTicker.C:
if b.waveOffset > -b.Width() {
b.waveOffset -= 3
} else {
b.waveOffset = (b.waveOffset % 3)
}
b.Update()
}
}
}()
}
气泡效果,无法非就是做动画, 画上数个半透明圆,让它向上移动,超出距离,能不画了.
代码如下:
// 画气泡
func (b *WaveBallWidget) drawBubbles() {
b.painter.Save()
// 设置颜色。
b.painter.SetPen3(core.Qt__NoPen)
// 半透明
b.painter.SetBrush(gui.NewQBrush3(gui.NewQColor3(0xFF, 0xFF, 0xFF, 0x5F), core.Qt__SolidPattern))
// 画气泡
for i := 0; i < BUBBLEMAX; i++ {
var bb = bubbleList[i]
if bb != nil {
b.painter.DrawEllipse3(bb.x+b.pX+b.X(), bb.y+b.pY+b.Y(), bb.w, bb.h)
}
}
b.painter.Restore()
}
// 开始气泡效果
func (b *WaveBallWidget) StartBubble() {
b.BubbleTicker = time.NewTicker(50 * time.Millisecond)
go func() {
for {
if b.BubbleTicker == nil {
time.Sleep(1)
} else {
select {
case <-b.BubbleTicker.C:
// 外环转动
b.angle += 5
if b.angle >= 360 {
b.angle = float64(int(b.angle) % 5)
}
// 检测并移动气泡。
for i := 0; i < BUBBLEMAX; i++ {
var bb = bubbleList[i]
if bb == nil {
// 创建气泡,
// 随机位置,随机大小(5 到 (width/BUBBLEMAX-6)),随机速度
var u = (b.Width() - 50) / (BUBBLEMAX)
var row = rand.Intn(u)
var width = 5 + rand.Intn(u-5)
var speed = 1 + rand.Intn(4)
// 左右下,各留出25个像素
bubbleList[i] = &Bubble{row*width + width/2 + 25, b.Height() - 25 - width/2, width, width, speed}
bb = bubbleList[i]
}
// 移动气泡,只是改变了y坐标
bb.y -= bb.s
y := float64(b.Height()) * float64((1 - float64(b.progress)/100.0))
if float64(bb.y) < y {
bubbleList[i] = nil
}
}
b.Update()
}
}
}
}()
}
好了说完了!!!
忘了说了,qt库中绘图代码中有个巨坑
看到那个b.pX, b.pY了么(parentX, parentY简写), 这个就是父控件的左上角的坐标位置; 绘图时,必须使用全局坐标,而不是相对于该控件的坐标,否则,你会看不到效果;因为超出该控件的绘制是无法看到的。