第11章 GUI Page455~458 步骤二十:实现各类图元的“命中”判断

本文介绍了如何在C++中新增头文件和源文件,实现几何形状如直线、方框和圆的碰撞检测函数,同时讨论了在已有派生类情况下添加纯虚接口的方法,提倡为每个派生类提供空实现以避免编译问题。
摘要由CSDN通过智能技术生成

新增头文件:

新增源文件:hit_test_tool.cpp

//hit_test_tool.cpp
#include "hit_test_tool.hpp"

#include <cmath>
#include <algorithm>

//求两点间的直线距离(已知直角三角形两直角边长度,求斜边长度)
double get_line_length(int startX, int startY
                       , int endX, int endY)
{
    double dx = endX - startX;
    double dy = endY - startY;

    return std::sqrt(dx * dx + dy * dy);
}
//点testX, testY是否在给定的线段上
bool OnLineSegment(int startX, int startY
                   , int endX, int endY
                   , int testX, int testY)
{
    //允许的误差值,否则我们点半天也点不到线上
    const double MARGIN_FOR_LINE_HITTEST_ERROR = 0.01;

    double l1 = get_line_length(startX, startY, testX, testY);
    double l2 = get_line_length(testX, testY, endX, endY);
    double l = get_line_length(startX, startY, endX, endY);

    return std::abs(l - (l1 + l2)) <= MARGIN_FOR_LINE_HITTEST_ERROR;
}
//点testX, testY是否在给定的方框内
bool InRect(int startX, int startY
            , int endX, int endY
            , int testX, int testY
            , bool hollow) //hollow:是否“中空”
{
    int minorX = std::min(startX, endX);//startX,endX中的较小值
    int minorY = std::min(startY, endY);

    int biggishX = std::max(startX, endX);
    int biggishY = std::max(startY, endY);

    if(hollow)
    {
        //如果“中空”,就简单粗暴地判断是不是在框的四条边线上
        return OnLineSegment(minorX, minorY, minorX, biggishY, testX, testY)
            || OnLineSegment(minorX, minorY, biggishX, minorY, testX, testY)
            || OnLineSegment(biggishX, biggishY, biggishX, minorY, testX, testY)
            || OnLineSegment(biggishX, biggishY, minorX, biggishY, testX, testY);
    }
    else
    {
        return (testX >= minorX && testX <= biggishX)
                && (testY >= minorY && testY <= biggishY);
    }
}
//点testX, testY是否在给定的圆内
bool InCircle(int centerX, int centerY, int radius
              , int testX, int testY
              , bool hollow) //hollow:是否“中空”
{
    double distance = get_line_length(centerX, centerY, testX, testY);

    const double MARGIN_FOR_CIRCLE_HITTEST_ERROR = 2.5;

    if(hollow)
    {
        return std::abs(distance - radius) <= MARGIN_FOR_CIRCLE_HITTEST_ERROR;
    }
    else
    {
        return distance <= radius;
    }
}

为抽象类添加新接口:

小提示:在已经有不少派生类的情况下调试基类的新接口

一旦为IItem添加一个纯虚的接口,比如前述的  IsHitOn(), 就意味着我们不得不为所有当前已经存在的派生类都实现该接口之后,程序才能够编译通过,运行起来接受测试。小窍门是暂时将IItem::IsHitOn 改成一个空的实现,默认返回false。等后续完成各派生类实现了,才将它恢复成纯虚接口, 不推荐这样做,推荐的做法是为每个派生类写一个空的实现,先简单返回false

实现接口:

直线:

item_line.hpp

item_line.cpp

其他图形,接口IsHitOn(int x, int y)暂时实现为一个空实现:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值