我正在使用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];
}
}
}
这很好用,除了我看到瓷砖之间的颜色有些错误。我想这是由于一些抗锯齿或类似的。请参阅下面的屏幕截图(希望您也可以看到相同的问题......其中一些黑色线条与瓷砖重叠):
因此我有以下问题:
更新
const int GRIDSIZE = 16;
cellWidth = (frame.size.width / GRIDSIZE);
cellHeight = (frame.size.height / GRIDSIZE);
答案 0 :(得分: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];
答案 1 :(得分:3)
首先,确保您的笔触颜色不是黑色或灰色。 (你正在设置color
但是是中风还是填充颜色?我永远不会记得。)
其次,如果您只是填充绿色,然后在其上绘制红色方块,反之亦然,会发生什么?
还有其他方法可以做你想做的事。您可以使用CICheckerboardGenerator
代替您的背景。
或者,您也可以使用手动填写的CGBitmapContext
。
答案 2 :(得分:3)
首先,如果您实际上不希望矩形有边框,则不应拨打[path stroke]
。
其次,创建填充矩形的bezier路径是过度的。您可以使用NSRectFill(r)
执行相同的操作。这个函数可能更有效率,我怀疑不太容易为你的浮点数引入舍入错误 - 我假设你意识到如果你想要像素精确的矩形,你的浮点数不能有一个小数部分。我相信如果您的视图的宽度和高度是GRIDSIZE
的倍数并且您使用NSRectFill
,那么工件应该消失。
第三,如果视图的宽度和高度不是GRIDSIZE
的倍数,那么关于如何绘制电路板的问题显而易见。如果您的视图大小是固定的并且是该常量的倍数,那么这当然不是问题。但是,如果不是这样,首先必须澄清您希望如何处理宽度或高度的剩余部分。应该有边境吗?行或列中的最后一个单元格是否应占用剩余部分?或者它应该在行或列的单元格中平均分配?您可能必须接受不同宽度和/或高度的单元格。解决问题的最佳方案取决于您的具体要求。
您可能还想了解绘制棋盘的其他方法,例如:使用CICheckerboardGenerator
或使用图像([NSColor colorWithPatternImage:yourImage]
)创建图案颜色,然后用它填充整个视图。
还有可能(暂时)关闭抗锯齿功能。为此,请将以下行添加到绘图方法的开头:
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
我最后的观察是关于你的一般方法。如果你的游戏将有更复杂的图形和动画,例如片段的动画移动,使用OpenGL可能会更好。
答案 3 :(得分:1)
你的方块重叠。 ix + CELLWIDTH
与循环的下一次迭代中的ix
坐标相同。
您可以通过将笔触颜色明确设置为透明或不调用stroke
来解决此问题。
[color set];
[[NSColor clearColor] setStroke];
或
[path fill];
// not [path stroke];
答案 4 :(得分:1)
从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
}