0

Cocoa を使用して Mac OS X 用の小さなボードゲームを書いています。実際のグリッドは次のように描画されます。

- (void)drawRect:(NSRect)rect
{
    for (int x=0; x < GRIDSIZE; x++) {
        for (int y=0; y < GRIDSIZE; y++) {          

            float ix = x*cellWidth;
            float iy = y*cellHeight;

            NSColor *color = (x % 2 == y % 2) ? boardColors[0] : boardColors[1];
            [color set];

            NSRect r = NSMakeRect(ix, iy, cellWidth, cellHeight);

            NSBezierPath *path = [NSBezierPath bezierPath];
            [path appendBezierPathWithRect:r];

            [path fill];
            [path stroke];  
        }
    }   
}

タイル間の色にいくつかのエラーが見られることを除けば、これはうまく機能します。これはアンチエイリアシングなどによるものだと思います。以下のスクリーンショットを参照してください (うまくいけば、同じ問題も見られると思います...タイルが重なっているところに黒い線がいくつかあります):

レンダリングされたボード

したがって、私はこれらの質問があります:

  1. サイズ変更可能/スケーラブルなボードを維持しながら、これらのグラフィック アーティファクトを削除する方法はありますか?
  2. Core Graphics や OpenGL などの他のグラフィカル ライブラリを使用する必要がありますか?

アップデート:

const int GRIDSIZE = 16;
cellWidth = (frame.size.width / GRIDSIZE);
cellHeight = (frame.size.height / GRIDSIZE);
4

5 に答える 5

8

鮮明な長方形が必要な場合は、下にあるピクセルと一致するように座標を揃える必要があります。NSViewには、この目的のためのメソッドがあります: - (NSRect)backingAlignedRect:(NSRect)aRect options:(NSAlignmentOptions)options. グリッドを描画するための完全な例を次に示します。

const NSInteger GRIDSIZE = 16;

- (void)drawRect:(NSRect)dirtyRect {
    for (NSUInteger x = 0; x < GRIDSIZE; x++) {
        for (NSUInteger y = 0; y < GRIDSIZE; y++) {
            NSColor *color = (x % 2 == y % 2) ? [NSColor greenColor] : [NSColor redColor];
            [color set];
            [NSBezierPath fillRect:[self rectOfCellAtColumn:x row:y]];
        }
    }
}

- (NSRect)rectOfCellAtColumn:(NSUInteger)column row:(NSUInteger)row {
    NSRect frame = [self frame];
    CGFloat cellWidth = frame.size.width / GRIDSIZE;
    CGFloat cellHeight = frame.size.height / GRIDSIZE;
    CGFloat x = column * cellWidth;
    CGFloat y = row * cellHeight;
    NSRect rect = NSMakeRect(x, y, cellWidth, cellHeight);
    NSAlignmentOptions alignOpts = NSAlignMinXNearest | NSAlignMinYNearest |
            NSAlignMaxXNearest | NSAlignMaxYNearest ;
    return [self backingAlignedRect:rect options:alignOpts];
}

strokeゲームボードを引く必要はないことに注意してください。ピクセルで整列されたストロークを描画するには、Cocoa の座標が実際にはピクセルの左下隅を指していることを覚えておく必要があります。線を鮮明にするには、座標がピクセルの中心を指すように、座標を整数座標から半ピクセル分オフセットする必要があります。たとえば、グリッド セルの鮮明な境界線を描画するには、次のようにします。

NSRect rect = NSInsetRect([self rectOfCellAtColumn:column row:row], 0.5, 0.5);
[NSBezierPath strokeRect:rect];
于 2013-08-29T17:58:09.693 に答える
3

まず第一に、実際に長方形に境界線を持たせたくない場合は、 を呼び出すべきではありません[path stroke]

次に、四角形を塗りつぶすためのベジエ パスを作成するのはやり過ぎです。で同じことができますNSRectFill(r)。この関数はおそらくより効率的であり、フロートに丸めエラーが発生する可能性が低いと思われます – ピクセル精度の長方形が必要な場合、フロートに小数部分があってはならないことに気付いていると思います。ビューの幅と高さが の倍数でGRIDSIZE、 を使用するNSRectFillと、アーティファクトはなくなるはずです。

3 番目に、ビューの幅と高さが の倍数でない場合にボードをどのように描画するかという明らかな問題がありますGRIDSIZE。ビューのサイズが固定されていて、その定数の倍数である場合、これはもちろん問題ではありません。ただし、そうでない場合は、幅または高さの残りの部分をどのように処理するかを最初に明確にする必要があります。国境があるべきか?行または列の最後のセルが残りを占有する必要がありますか? それとも、行または列のセル間で均等に分散する必要がありますか? さまざまな幅や高さのセルを受け入れなければならない場合があります。問題の最適な解決策は、正確な要件によって異なります。

また、チェッカーボードを描画する他の方法を検討することもできます。たとえばCICheckerboardGenerator、画像 ( ) でパターン カラーを使用または作成し、それで[NSColor colorWithPatternImage:yourImage]ビュー全体を塗りつぶします。

アンチエイリアシングを (一時的に) オフにすることもできます。これを行うには、描画メソッドの先頭に次の行を追加します。

  [[NSGraphicsContext currentContext] setShouldAntialias:NO];

私の最後の観察は、あなたの一般的なアプローチについてです。あなたのゲームがより複雑なグラフィックスやアニメーション、例えばアニメーション化されたピースの動きを持っている場合は、OpenGL を使用する方が良いかもしれません。

于 2013-08-24T20:59:06.473 に答える
3

まず、ストロークの色が黒またはグレーでないことを確認してください。(設定していますcolorが、それはストロークですか、それとも塗りつぶしですか?思い出せません。)

次に、単純に緑で塗りつぶし、その上に赤の四角を描くとどうなるでしょうか。その逆はどうでしょうか。

あなたが望むことをする他の方法もあります。代わりに を使用しCICheckerboardGeneratorて背景を作成できます。

CGBitmapContextまたは、手で埋めた を使用することもできます。

于 2013-08-22T04:15:35.507 に答える
2

iOS 6 以降、 を使用してチェッカーボード パターンを生成できますCICheckerboardGenerator

ここで強制アンラップを防ぐ必要がありますが、基本的な実装は次のとおりです。

var checkerboardImage: UIImage? {
    let filter = CIFilter(name: "CICheckerboardGenerator")!

    let width = NSNumber(value: Float(viewSize.width/16))
    let center = CIVector(cgPoint: .zero)
    let darkColor = CIColor.red
    let lightColor = CIColor.green
    let sharpness = NSNumber(value: 1.0)

    filter.setDefaults()
    filter.setValue(width, forKey: "inputWidth")
    filter.setValue(center, forKey: "inputCenter")
    filter.setValue(darkColor, forKey: "inputColor0")
    filter.setValue(lightColor, forKey: "inputColor1")
    filter.setValue(sharpness, forKey: "inputSharpness")

    let context = CIContext(options: nil)
    let cgImage = context.createCGImage(filter.outputImage!, from: viewSize)
    let uiImage = UIImage(cgImage: cgImage!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.up)

    return uiImage
}

Apple 開発者ドキュメント

于 2018-11-30T21:54:23.687 に答える