【问题标题】:How to draw a perfect squiggle in set card game with objective-c?如何用objective-c在卡牌游戏中画出完美的曲线?
【发布时间】:2014-08-19 15:58:13
【问题描述】:

我正在尝试在 Set Card Game 中绘制曲线。输出甚至不接近我想要的。我应该如何改进绘图?

  • 请忽略“我想要什么”图片中的阴影。我已经想出了如何做到这一点。问题是如何画出波浪线的形状
  • 这样做的目的是练习使用objective-c 进行绘图。所以在这里只使用png图片不是解决方案......

..

#define SQUIGGLE_CURVE_FACTOR 0.5
 - (UIBezierPath *)drawSquiggleAtPoint:(CGPoint)point
{
    CGFloat dx = self.bounds.size.width * SYMBOL_WIDTH_RATIO / 2;
    CGFloat dy = self.bounds.size.height * SYMBOL_HEIGHT_RATIO / 2;

    UIBezierPath *path = [[UIBezierPath alloc] init];
    CGFloat dsqx = dx * SQUIGGLE_CURVE_FACTOR;
    CGFloat dsqy = dy * SQUIGGLE_CURVE_FACTOR;
    [path moveToPoint:CGPointMake(point.x - dx, point.y)];
    [path addQuadCurveToPoint:CGPointMake(point.x - dsqx, point.y + dsqy) controlPoint:CGPointMake(point.x - dx, point.y + dy + dsqy)];
    [path addCurveToPoint:CGPointMake(point.x + dx, point.y) controlPoint1:point controlPoint2:CGPointMake(point.x + dx, point.y + dy * 2)];
    [path addQuadCurveToPoint:CGPointMake(point.x + dsqx, point.y - dsqy) controlPoint:CGPointMake(point.x + dx, point.y - dy - dsqy)];
    [path addCurveToPoint:CGPointMake(point.x - dx, point.y) controlPoint1:point controlPoint2:CGPointMake(point.x - dx, point.y - dy * 2)];

    return path;
}
  • 我得到了什么:

  • 我想要什么:


最终版本

- (UIBezierPath *)drawSquiggleAtPoint:(CGPoint)point
{
    CGSize size = CGSizeMake(self.bounds.size.width * SYMBOL_WIDTH_RATIO, self.bounds.size.height * SYMBOL_HEIGHT_RATIO);

    UIBezierPath *path = [[UIBezierPath alloc] init];
    [path moveToPoint:CGPointMake(104, 15)];
    [path addCurveToPoint:CGPointMake(63, 54) controlPoint1:CGPointMake(112.4, 36.9) controlPoint2:CGPointMake(89.7, 60.8)];
    [path addCurveToPoint:CGPointMake(27, 53) controlPoint1:CGPointMake(52.3, 51.3) controlPoint2:CGPointMake(42.2, 42)];
    [path addCurveToPoint:CGPointMake(5, 40) controlPoint1:CGPointMake(9.6, 65.6) controlPoint2:CGPointMake(5.4, 58.3)];
    [path addCurveToPoint:CGPointMake(36, 12) controlPoint1:CGPointMake(4.6, 22) controlPoint2:CGPointMake(19.1, 9.7)];
    [path addCurveToPoint:CGPointMake(89, 14) controlPoint1:CGPointMake(59.2, 15.2) controlPoint2:CGPointMake(61.9, 31.5)];
    [path addCurveToPoint:CGPointMake(104, 15) controlPoint1:CGPointMake(95.3, 10) controlPoint2:CGPointMake(100.9, 6.9)];

    [path applyTransform:CGAffineTransformMakeScale(0.9524*size.width/100, 0.9524*size.height/50)];
    [path applyTransform:CGAffineTransformMakeTranslation(point.x - size.width/2 - 3 * size.width /100, point.y - size.height/2 - 8 * size.height/50)];

    return path;
}

【问题讨论】:

  • 有多少种不同的曲线?似乎将一些 .png 文件添加到每个 .png 都是不同的曲线的项目中会更容易。
  • @user3386109 感谢您的建议。这样做的目的是在 iOS 中练习绘图。我会提出这个问题来澄清这一点。
  • 您可能希望根据最小或最大尺寸同时缩放 x 和 y,这样您就不会失去比例。

标签: objective-c drawing cs193p


【解决方案1】:

这是使用来自@user3386109 的路径曲线的 SwiftUI 版本(感谢您制作了完美的曲线)。我还添加了偏移和变换,以将曲线定位在其边界视图的中心并跨越其视图的整个宽度。

import SwiftUI

struct SquiggleShape: Shape {
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
                
        path.move(to: CGPoint(x: 104.0, y: 15.0))
        path.addCurve(to: CGPoint(x: 63.0, y: 54.0),
                      control1: CGPoint(x: 112.4, y: 36.9),
                      control2: CGPoint(x: 89.7, y: 60.8))
        path.addCurve(to: CGPoint(x: 27.0, y: 53.0),
                      control1: CGPoint(x: 52.3, y: 51.3),
                      control2: CGPoint(x: 42.2, y: 42.0))
        path.addCurve(to: CGPoint(x: 5.0, y: 40.0),
                      control1: CGPoint(x: 9.6, y: 65.6),
                      control2: CGPoint(x: 5.4, y: 58.3))
        path.addCurve(to: CGPoint(x: 36.0, y: 12.0),
                      control1: CGPoint(x: 4.6, y: 22.0),
                      control2: CGPoint(x: 19.1, y: 9.7))
        path.addCurve(to: CGPoint(x: 89.0, y: 14.0),
                      control1: CGPoint(x: 59.2, y: 15.2),
                      control2: CGPoint(x: 61.9, y: 31.5))
        path.addCurve(to: CGPoint(x: 104.0, y: 15.0),
                      control1: CGPoint(x: 95.3, y: 10.0),
                      control2: CGPoint(x: 100.9, y: 6.9))
        
        let pathRect = path.boundingRect
        path = path.offsetBy(dx: rect.minX - pathRect.minX, dy: rect.minY - pathRect.minY)
        
        let scale: CGFloat = rect.width / pathRect.width
        let transform = CGAffineTransform(scaleX: scale, y: scale)
        path = path.applying(transform)
        
        
        return path
            .offsetBy(dx: rect.minX - path.boundingRect.minX, dy: rect.midY - path.boundingRect.midY)
    }
}

【讨论】:

    【解决方案2】:

    我的曲线看起来像this。 可惜我不能直接插入图片

    这是我的方法。以及带有 CGrect 边界的波浪线比例尺

    typedef enum : NSUInteger
    {
    solidShading=1,
    stripedShading=2,
    openShading=3,
    numShading=4,
    } cardShading;
    
    
    -(void)drawSquiggleInBounds:(CGRect)bounds withColor:(UIColor *)color withShading:(cardShading)shading
    {
    if (shading > 3) {return;}
    
    UIBezierPath *path = [[UIBezierPath alloc] init];
    
    [color setStroke];
    
    path.lineWidth = 2;
    
    [path moveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.05, bounds.origin.y + bounds.size.height*0.40)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.35, bounds.origin.y + bounds.size.height*0.25)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.09, bounds.origin.y + bounds.size.height*0.15)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.18, bounds.origin.y + bounds.size.height*0.10)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.75, bounds.origin.y + bounds.size.height*0.30)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.40, bounds.origin.y + bounds.size.height*0.30)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.60, bounds.origin.y + bounds.size.height*0.45)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.97, bounds.origin.y + bounds.size.height*0.35)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.87, bounds.origin.y + bounds.size.height*0.15)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.98, bounds.origin.y + bounds.size.height*0.00)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.45, bounds.origin.y + bounds.size.height*0.85)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.95, bounds.origin.y + bounds.size.height*1.10)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.50, bounds.origin.y + bounds.size.height*0.95)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.25, bounds.origin.y + bounds.size.height*0.85)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.40, bounds.origin.y + bounds.size.height*0.80)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.35, bounds.origin.y + bounds.size.height*0.75)];
    
    [path addCurveToPoint:CGPointMake(bounds.origin.x + bounds.size.width*0.05, bounds.origin.y + bounds.size.height*0.40)
            controlPoint1:CGPointMake(bounds.origin.x + bounds.size.width*0.00, bounds.origin.y + bounds.size.height*1.10)
            controlPoint2:CGPointMake(bounds.origin.x + bounds.size.width*0.005, bounds.origin.y + bounds.size.height*0.60)];
    
    [path closePath];
    
    [self drawShading:shading withColor:color inPath:path];
    
    [path stroke];
    }
    

    还有我的着色方法:

    #define DISTANCE_BETWEEN_STRIPES 4
    
    -(void)drawShading:(cardShading)shading withColor:(UIColor *)color inPath:(UIBezierPath *)beziePath
    {
    switch (shading)
    {
        case 1:
            [color setFill];
            [beziePath fill];
            break;
        case 2:
            [self drawStripedShadingForPath:beziePath];
            break;
        default:
            break;
    }
    }
    
    -(void)drawStripedShadingForPath:(UIBezierPath *)pathOfSymbol
    {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    
    CGRect bounds = [pathOfSymbol bounds];
    UIBezierPath *path = [[UIBezierPath alloc] init];
    
    for (int i = 0; i < bounds.size.width; i += DISTANCE_BETWEEN_STRIPES)
    {
        [path moveToPoint:CGPointMake(bounds.origin.x + i, bounds.origin.y)];
        [path addLineToPoint:CGPointMake(bounds.origin.x + i, bounds.origin.y + bounds.size.height)];
    }
    
    [pathOfSymbol addClip];
    
    [path stroke];
    
    CGContextRestoreGState(UIGraphicsGetCurrentContext());
    }
    

    【讨论】:

      【解决方案3】:

      这里有一些代码可以很好地再现曲线

      - (void)drawSquiggle
      {
          CGContextRef context = UIGraphicsGetCurrentContext();
      
          // translate and scale the squiggle
          CGContextSaveGState( context );
          CGContextTranslateCTM( context, 0, 100 );
          CGContextScaleCTM( context, 2.0, 2.0 );
      
          // create the squiggle path
          CGContextMoveToPoint( context, 104.0, 15.0 );
          CGContextAddCurveToPoint( context, 112.4 , 36.9,   89.7,  60.8,   63.0,  54.0 );
          CGContextAddCurveToPoint( context,  52.3 , 51.3,   42.2,  42.0,   27.0,  53.0 );
          CGContextAddCurveToPoint( context,   9.6 , 65.6,    5.4,  58.3,    5.0,  40.0 );
          CGContextAddCurveToPoint( context,   4.6 , 22.0,   19.1,   9.7,   36.0,  12.0 );
          CGContextAddCurveToPoint( context,  59.2 , 15.2,   61.9,  31.5,   89.0,  14.0 );
          CGContextAddCurveToPoint( context,  95.3 , 10.0,  100.9,   6.9,  104.0,  15.0 );
      
          // draw the squiggle
          CGContextSetLineCap( context, kCGLineCapRound );
          CGContextSetLineWidth( context, 2.0 );
          CGContextStrokePath( context );
      
          // restore the graphics state
          CGContextRestoreGState( context );
      }
      

      这就是它产生的结果


      缩放和平移曲线

      有两种方法可以改变曲线的大小和位置。

      一种方法是更改​​所有传递给CGContextAddCurveToPoint 函数的数字。例如,如果您使用x = (x-3) * 0.9524 调整x 值并使用y = (y-8) * 0.9524 调整所有y 值,则曲线非常适合100x50 矩形。

      另一种方法是在绘制曲线之前更改绘图上下文的仿射变换。您可以应用平移和缩放转换来在任何您想要的地方放置/调整曲线。请注意,应用转换的顺序很重要。此外,您可以保存和恢复图形状态,以便仅将转换应用于曲线,而不应用于您正在绘制的其他项目。上面的代码将曲线向下移动了 100 像素,使其变大了两倍。

      【讨论】:

      • 感谢代码...我投了赞成票。实际上我需要一个算法,它应该基于给定的点和卡片的大小。所以我可以在一张卡片上画多个(两个或三个)曲线。
      • @CaffHuang 我用一些关于缩放和翻译曲线的注释修改了答案。请注意,代码 sn-p 已更改以演示概念。
      • 已回答。非常感谢你的帮助。我已经使用 UIBezierPath 将我的代码更新为原始代码。 applyTransform 真的很有帮助。
      【解决方案4】:

      我在 Illustrator 中画了这个,然后将它移到 swift 中。这是我能够创建的曲线。如果您查看提问者的最终解决方案,将其转换为 Objective-C 应该是微不足道的。

          func getSquiggle(_ bounds: CGRect) -> UIBezierPath {
          // Based on: https://stackoverflow.com/questions/25387940/how-to-draw-a-perfect-squiggle-in-set-card-game-with-objective-c
          let startPoint = CGPoint(x: 76.5, y: 403.5)
          let curves = [ // to, cp1, cp2
              (CGPoint(x:  199.5, y: 295.5), CGPoint(x: 92.463, y: 380.439),
                                             CGPoint(x: 130.171, y: 327.357)),
              (CGPoint(x:  815.5, y: 351.5), CGPoint(x: 418.604, y: 194.822),
                                             CGPoint(x: 631.633, y: 454.052)),
              (CGPoint(x: 1010.5, y: 248.5), CGPoint(x: 844.515, y: 313.007),
                                             CGPoint(x: 937.865, y: 229.987)),
              (CGPoint(x: 1057.5, y: 276.5), CGPoint(x: 1035.564, y: 254.888),
                                             CGPoint(x: 1051.46, y: 270.444)),
              (CGPoint(x:  993.5, y: 665.5), CGPoint(x: 1134.423, y: 353.627),
                                             CGPoint(x: 1105.444, y: 556.041)),
              (CGPoint(x:  860.5, y: 742.5), CGPoint(x: 983.56, y: 675.219),
                                             CGPoint(x: 941.404, y: 715.067)),
              (CGPoint(x:  271.5, y: 728.5), CGPoint(x: 608.267, y: 828.077),
                                             CGPoint(x: 452.192, y: 632.571)),
              (CGPoint(x:  101.5, y: 803.5), CGPoint(x: 207.927, y: 762.251),
                                             CGPoint(x: 156.106, y: 824.214)),
              (CGPoint(x:   49.5, y: 745.5), CGPoint(x: 95.664, y: 801.286),
                                             CGPoint(x: 73.211, y: 791.836)),
              (startPoint, CGPoint(x: 1.465, y: 651.628),
                           CGPoint(x: 1.928, y: 511.233)),
          ]
      
          // Draw the squiggle
          let path = UIBezierPath()
          path.move(to: startPoint)
          for (to, cp1, cp2) in curves {
              path.addCurve(to: to, controlPoint1: cp1, controlPoint2: cp2)
          }
          path.close()
          // Your code to scale, rotate and translate the squiggle
      
          return path
      

      【讨论】:

        【解决方案5】:

        我不熟悉任何领域中“完美”曲线的正式定义?我知道套牌游戏当然是套牌的,但它并不完美。

        【讨论】:

          猜你喜欢
          • 2018-03-21
          • 2011-07-01
          • 2018-04-02
          • 2013-05-12
          • 1970-01-01
          • 2017-06-04
          • 1970-01-01
          • 2013-04-17
          • 1970-01-01
          相关资源
          最近更新 更多