以前的电视机待机时,都有一个球在界面弹来弹去,碰到边界则改变颜色和方向。
设计算法实现该效果,qt实现界面,C++实现运动轨迹,及颜色变化。
详细注释
效果如图
运动轨迹控制类头文件
#ifndef CMOTIONCONTROL_H
#define CMOTIONCONTROL_H
#include <vector>
#include <string>
/**
* @brief 坐标信息结构体
* @author GGX
* @date 2023-08-13
*/
struct SPoint
{
int x;
int y;
/**
* @brief 重载操作符
* @param [in] point 自增信息
* @return 无
* @author GGX
* @date 2023-08-13
*/
SPoint & operator+=(SPoint point)
{
x += point.x;
y += point.y;
return *this;
}
/**
* @brief 判断X是否在范围内
* @param [in] lX 范围左区间
* @param [in] rX 范围右区间
* @return true 在范围内,false不在范围内
* @author GGX
* @date 2023-08-13
*/
bool isRangeX(int lX, int rX)
{
return x > lX && x < rX;
}
/**
* @brief 判断Y是否在范围内
* @param [in] lY 范围左区间
* @param [in] rY 范围右区间
* @return true 在范围内,false不在范围内
* @author GGX
* @date 2023-08-13
*/
bool isRangeY(int lY, int rY)
{
return y > lY && y < rY;
}
};
/**
* @brief 弹球控制类
* @author GGX
* @date 2023-08-13
*/
class CMotionControl
{
public:
CMotionControl();
/**
* @brief 设置坐标位置
* @param [in] x 坐标轴
* @param [in] y 坐标轴
* @return 无
* @author GGX
* @date 2023-08-13
*/
void setPoint(int x, int y);
/**
* @brief 获取坐标位置
* @param 无
* @return SPoint 坐标位置
* @author GGX
* @date 2023-08-13
*/
SPoint getPoint();
/**
* @brief 设置范围右区间
* @param [in] x 坐标轴
* @param [in] y 坐标轴
* @return SPoint 坐标位置
* @author GGX
* @date 2023-08-13
*/
void setRange(int x, int y);
/**
* @brief 设置步进值
* @param [in] SPoint x,y步进值
* @return 无
* @author GGX
* @date 2023-08-13
*/
void setStep(SPoint step);
/**
* @brief 在坐标范围内移动弹球位置
* @param [in] SPoint x,y步进值
* @return 无
* @author GGX
* @date 2023-08-13
*/
bool move();
/**
* @brief 获取弹球颜色
* @param 无
* @return std::string 弹球颜色
* @author GGX
* @date 2023-08-13
*/
std::string color();
/**
* @brief 获取弹球边框颜色
* @param 无
* @return std::string 弹球边框颜色
* @author GGX
* @date 2023-08-13
*/
std::string borderColor();
protected:
/**
* @brief 初始化弹球颜色
* @param 无
* @return 无
* @author GGX
* @date 2023-08-13
*/
void initColor();
private:
SPoint m_Point; //弹球位置
SPoint m_Range; //范围右区间
SPoint m_Step; //步进值
size_t m_indexColor; //当前弹球颜色
std::vector<std::string> m_colors; //弹球颜色容器
};
#endif // CMOTIONCONTROL_H
运动轨迹控制类源文件
#include "cmotioncontrol.h"
CMotionControl::CMotionControl()
{
m_Point = {0, 0};
m_Range = {0, 0};
m_Step = {0, 0};
initColor();
}
void CMotionControl::setPoint(int x, int y)
{
m_Point = {x, y};
}
SPoint CMotionControl::getPoint()
{
return m_Point;
}
void CMotionControl::setRange(int x, int y)
{
m_Range = {x, y};
}
void CMotionControl::setStep(SPoint step)
{
m_Step = step;
}
bool CMotionControl::move()
{
//弹球是否碰壁
bool bChange = false;
if (!m_Point.isRangeX(0, m_Range.x))
{
//若是超出范围,则按反方向移动
m_Step.x = -m_Step.x;
bChange = true;
}
if (!m_Point.isRangeY(0, m_Range.y))
{
//若是超出范围,则按反方向移动
m_Step.y = -m_Step.y;
bChange = true;
}
if (bChange)
{
//弹球碰壁,则变换颜色
m_indexColor++;
}
if (m_indexColor >= m_colors.size())
{
m_indexColor = 0;
}
//弹球位置移动
m_Point += m_Step;
return bChange;
}
std::string CMotionControl::color()
{
return m_colors.at(m_indexColor);
}
std::string CMotionControl::borderColor()
{
return m_colors.at(m_colors.size() - m_indexColor - 1);
}
void CMotionControl::initColor()
{
m_indexColor = 0;
// m_colors.emplace_back("color0");
// m_colors.emplace_back("color1");
m_colors.emplace_back("black");
m_colors.emplace_back("white");
m_colors.emplace_back("darkGray");
m_colors.emplace_back("gray");
m_colors.emplace_back("lightGray");
m_colors.emplace_back("red");
m_colors.emplace_back("green");
m_colors.emplace_back("blue");
m_colors.emplace_back("darkGray");
m_colors.emplace_back("cyan");
m_colors.emplace_back("magenta");
m_colors.emplace_back("yellow");
m_colors.emplace_back("darkRed");
m_colors.emplace_back("darkGray");
m_colors.emplace_back("darkGreen");
m_colors.emplace_back("darkBlue");
m_colors.emplace_back("darkCyan");
m_colors.emplace_back("darkMagenta");
m_colors.emplace_back("darkYellow");
// m_colors.emplace_back("transparent");
}
QT界面头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <qtimer.h>
class CMotionControl;
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void slTimer();
void on_start_clicked();
private:
Ui::MainWindow *ui;
int m_step; //每次移动的像素
CMotionControl *m_pMotionControl; //控制弹球运动轨迹及颜色
QTimer *m_pTimer; //定时器,触发移动
};
#endif // MAINWINDOW_H
QT界面源文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qdebug.h"
#include "cmotioncontrol.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_pTimer = new QTimer(this);
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(slTimer()));
m_step = 10;
m_pMotionControl = new CMotionControl();
m_pMotionControl->setStep({m_step, m_step});
}
MainWindow::~MainWindow()
{
delete ui;
delete m_pTimer;
delete m_pMotionControl;
}
void MainWindow::slTimer()
{
//移动弹球坐标
bool bChange = m_pMotionControl->move();
//获取移动后的位置
SPoint point = m_pMotionControl->getPoint();
//移动弹球
ui->label_point->move(point.x, point.y);
//弹球碰壁则改变颜色
if (bChange)
{
QString bgColor = m_pMotionControl->color().c_str();
QString bdColor = m_pMotionControl->borderColor().c_str();
int length = 100;
QString strColor = "";
strColor.append(QString("min-width:%1px;").arg(length));
strColor.append(QString("min-height:%1px;").arg(length));
strColor.append(QString("max-width:%1px;").arg(length));
strColor.append(QString("max-height:%1px;").arg(length));
strColor.append(QString("border-radius:%1px;").arg(length / 2));
strColor.append(QString("border:%1px solid %2;").arg(3).arg(bdColor));
strColor.append(QString("background-color:%1;").arg(bgColor));
ui->label_point->setStyleSheet(QString("QLabel{%1}").arg(strColor)); //设置样式表
}
qDebug() << "SPoint: {" << point.x << ", " << point.y << "}";
}
void MainWindow::on_start_clicked()
{
//设置弹球起点
m_pMotionControl->setPoint(ui->label_point->pos().x(),
ui->label_point->pos().y());
//设置弹球范围
m_pMotionControl->setRange(width() - ui->label_point->width() - m_step,
height() - ui->label_point->height() - m_step);
int msec = 50;
//启停定时器
if (m_pTimer->isActive())
{
m_pTimer->stop();
}
else
{
m_pTimer->start(msec);
}
}
码云地址:svn://gitee.com/gongguixing/daily-learning/qt_ui/Pinball