使用GDI和QT进行几何绘图

基本几何画图步骤:

  •  创建画笔:默认颜色 BLACK

           CreatePen(...)

  • 创建画刷: 默认画刷颜色为NULL

         CreateSolidBrush(...)

         CreateHatchBrush(...)  阴影画刷

         CreatePatternBrush(...) 不常用

  • 拿起画笔:SelectObject(...)
  • 画线条:
    • LineTo(...) 参数只有终点,当前点默认是(0,0) ,绘制后终点变成了当前点
    • MoveToEx(...) 移动画笔的当前点
  •   画矩形 Rectangle(...)
  • 删除画笔:DeleteObject(...)

游戏随机数系统

计算机一般情况下只能生成伪随机数:计算机产生随机数的过程,是根据一个数为基准以某个递推公式 推算出来的一系列数,但这系列数很大的时候,就符合正态分布,从而相当于产生了随机数

  • srand((unsigned)time(NULL)) 用系统时间初始化随机种子
  • rand(...) 生成随机数

几种随机数的简单算法

用到的时候再去看

算法+绘图

设计:

效果:每次运行时,都会得到不同的画笔和画刷

基于GDI全局变量的定义

HPEN		g_hPen[7]={0}; 
HBRUSH	g_hBrush[7]={0}; 
int				g_iPenStyle[7] = {PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT,PS_NULL,PS_INSIDEFRAME};  
int				g_iBrushStyle[6] = {HS_VERTICAL,HS_HORIZONTAL,HS_CROSS,HS_DIAGCROSS,HS_FDIAGONAL,HS_BDIAGONAL};  
PlaySound(L"AIR - 夏影.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循环播放背景音乐

随机生成画笔和画刷的颜色

BOOL Game_Init( HWND hwnd )
{
	g_hdc = GetDC(hwnd);
	srand((unsigned)time(NULL));

	
	for(int i=0;i<=6;i++)
	{
			g_hPen[i] = CreatePen(g_iPenStyle[i],1,RGB(rand()%256,rand()%256,rand()%256));
		if(i==6)
			g_hBrush[i] = CreateSolidBrush(RGB(rand()%256,rand()%256,rand()%256));
		else
			g_hBrush[i] = CreateHatchBrush(g_iBrushStyle[i],RGB(rand()%256,rand()%256,rand()%256));
	}

	Game_Paint(hwnd);
	ReleaseDC(hwnd,g_hdc);
	return TRUE;
}

绘图逻辑

VOID Game_Paint( HWND hwnd )
{
	//定义一个y坐标值
	int y=0;

	//一个for循环,用7种不同的画笔绘制线条
	for(int i=0;i<=6;i++)
	{
		y = (i+1) * 70;

		SelectObject(g_hdc,g_hPen[i]);//将对应的画笔选好
		MoveToEx(g_hdc,30,y,NULL);	 //“光标”移动到对应的(30,y)坐标处
		LineTo(g_hdc,100,y);			 //从(30,y)坐标处向(100,y)绘制线段
	}

	/*注意上面画完后y=420,下面画矩形的时候还有用*/
	//定义两个x坐标值
	int x1 = 120;
	int x2 = 190;

	//用7种不同的画刷填充矩形
	for(int i=0;i<=6;i++)
	{
		SelectObject(g_hdc,g_hBrush[i]);  //选用画刷
		Rectangle(g_hdc,x1,70,x2,y);	 //画出一个封闭的矩形,矩形左上角坐标为(x1,50),右下角坐标为(x2,y)
		x1 += 90;
		x2 += 90;
	}
}

 释放句柄

BOOL Game_CleanUp( HWND hwnd )
{
	//一个for循环,释放掉所有的画笔和画刷句柄
	for (int i=0;i<=6;i++)
	{
		DeleteObject(g_hPen[i]);
		DeleteObject(g_hBrush[i]);
	}
	return TRUE;
}

使用QT框架画图

 Graphics/View框架:存放显示处理那些对图形元素进行操作的交互命令

QGraphicsView:负责显示一个场景中的部分或全部图形元素,拥有自己的坐标系,并和具体显示设备密切相关

QGraphicsItem:被显示的图形元素

QGraphicsScene:囊括了所有的图形元素的场景

        维护一个列表: 记录哪些图形元素被选中

               数据结构:记录哪个或者哪些图形元素获得聚焦

图形元素的碰撞

检测原理:

QGraphicsItem中的虚函数shape()负责返回其自身的轮廓,

QGraphicsScene中的colidingItems()负责查询场景中每个图形元素的轮廓,判断哪些元素和某个指定的元素相撞

相撞的老鼠

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//用系统时间初始化随机种子 


    QGraphicsScene scene;//场景对象
    scene.setSceneRect(-300, -300, 600, 600);

    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
    for (int i = 0; i < MouseCount; ++i) { //6只老鼠
        Mouse *mouse = new Mouse;//老鼠对象
        mouse->setPos(::sin((i * 6.28) / MouseCount) * 200,
                      ::cos((i * 6.28) / MouseCount) * 200);//设置位置
        scene.addItem(mouse);//添加到场景中
    }
    QGraphicsView view(&scene);//负责显示一个场景中的部分元素或全部全部元素
    view.setRenderHint(QPainter::Antialiasing);
    view.setBackgroundBrush(QPixmap(":/images/cheese.jpg"));//甜心图片

    view.setCacheMode(QGraphicsView::CacheBackground);
    view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    view.setDragMode(QGraphicsView::ScrollHandDrag);

    view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice"));
    view.resize(400, 300);
    view.show();

    QTimer timer; //定时器对象
    QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance())); //信号槽(定时器信号-advance)
    timer.start(1000 / 30); //定时器(3s一次的频率进行图形元素的advance())

    return app.exec();
}

#include <QGraphicsItem>

class Mouse : public QGraphicsItem
{
public:
    Mouse();
    //返回包围一个老鼠图形的最小矩形
    QRectF boundingRect() const override;
    //返回老鼠的精确外形
    QPainterPath shape() const override;
    //当需要绘制某个图形元素,这个函数会被调用
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget) override;

protected:
    //更新老鼠的位置,眼睛的颜色
    void advance(int step) override;

private:
    qreal angle;
    qreal speed;
    qreal mouseEyeDirection;
    QColor color;
};

作用:返回包围一个老鼠图形的最小矩形

实现思路:

static qreal normalizeAngle(qreal angle)
{
    while (angle < 0)
        angle += TwoPi;
    while (angle > TwoPi)
        angle -= TwoPi;
    return angle;
}

作用:初始化变量值,设置老鼠出现的角度方向

Mouse::Mouse()
    : angle(0), speed(0), mouseEyeDirection(0),
      color(qrand() % 256, qrand() % 256, qrand() % 256)
{
    setRotation(qrand() % 360 );
}

作用:返回包围一个老鼠图形的最小矩形

QRectF Mouse::boundingRect() const
{
    qreal adjust = 0.5;
    return QRectF(-18 - adjust, -22 - adjust,
                  36 + adjust, 60 + adjust);
}

 作用:返回老鼠的精确外形

QPainterPath Mouse::shape() const
{
    QPainterPath path;
    path.addRect(-10, -20, 20, 40);
    return path;
}

作用:当需要绘制某个图形元素,这个函数会被调用

实现思路:通过画椭圆和坐标位置拼接老鼠的各个器官

void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    // Body
    painter->setBrush(color);
    painter->drawEllipse(-10, -20, 20, 40);

    // Eyes
    painter->setBrush(Qt::white);
    painter->drawEllipse(-10, -17, 8, 8);
    painter->drawEllipse(2, -17, 8, 8);

    // Nose
    painter->setBrush(Qt::black);
    painter->drawEllipse(QRectF(-2, -22, 4, 4));

    //eyeball(眼球)
    painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4));
    painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4));

    // Ears
    painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red);//碰撞检测
    painter->drawEllipse(-17, -12, 16, 16);
    painter->drawEllipse(1, -12, 16, 16);

    // Tail
    QPainterPath path(QPointF(0, 20));
    path.cubicTo(-5, 22, -5, 22, 0, 25);
    path.cubicTo(5, 27, 5, 32, 0, 30);
    path.cubicTo(-5, 32, -5, 42, 0, 35);
    painter->setBrush(Qt::NoBrush);
    painter->drawPath(path);
}

作用:更新老鼠的位置,眼睛的颜色

实现思路:待研究

void Mouse::advance(int step)
{
    if (!step)
        return;

    // Don't move too far away

    QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0));
    if (lineToCenter.length() > 150) {
        qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length());
        if (lineToCenter.dy() < 0)
            angleToCenter = TwoPi - angleToCenter;
        angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2);

        if (angleToCenter < Pi && angleToCenter > Pi / 4) {
            // Rotate left
            angle += (angle < -Pi / 2) ? 0.25 : -0.25;
        } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) {
            // Rotate right
            angle += (angle < Pi / 2) ? 0.25 : -0.25;
        }
    } else if (::sin(angle) < 0) {
        angle += 0.25;
    } else if (::sin(angle) > 0) {
        angle -= 0.25;

    }


    // Try not to crash with any other mice

    QList<QGraphicsItem *> dangerMice = scene()->items(QPolygonF()
                                                       << mapToScene(0, 0)
                                                       << mapToScene(-30, -50)
                                                       << mapToScene(30, -50));
    foreach (QGraphicsItem *item, dangerMice) {
        if (item == this)
            continue;
        
        QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0));
        qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length());
        if (lineToMouse.dy() < 0)
            angleToMouse = TwoPi - angleToMouse;
        angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2);

        if (angleToMouse >= 0 && angleToMouse < Pi / 2) {
            // Rotate right
            angle += 0.5;
        } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) {
            // Rotate left
            angle -= 0.5;

        }

    }


    // Add some random movement

    if (dangerMice.size() > 1 && (qrand() % 10) == 0) {
        if (qrand() % 1)
            angle += (qrand() % 100) / 500.0;
        else
            angle -= (qrand() % 100) / 500.0;
    }
    speed += (-50 + qrand() % 100) / 100.0;

    qreal dx = ::sin(angle) * 10;
    mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5;

    setRotation(rotation() + dx);
    setPos(mapToParent(0, -(3 + sin(speed) * 3)));
}

设计图

 效果图

 

哦,我的天啊,好累啊,给自己点个赞!

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值