[英]Drawing board/grid with Cocoa
我正在使用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);
如果要使用清晰的矩形,则需要对齐坐标,以使其与基础像素匹配。 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
即可绘制游戏板。 要绘制像素对齐的笔划,您需要记住可可中的坐标实际上指向像素的左下角。 要使线条清晰,您需要将坐标从整数坐标偏移半个像素,以便坐标指向像素中心。 例如,要为网格单元格绘制清晰的边框,可以执行以下操作:
NSRect rect = NSInsetRect([self rectOfCellAtColumn:column row:row], 0.5, 0.5);
[NSBezierPath strokeRect:rect];
首先,请确保您的笔触颜色不是黑色或灰色。 (您正在设置color
但是是笔触还是填充颜色?我记不起来了。)
其次,如果仅用绿色填充,然后在其上绘制红色方块,反之亦然,会发生什么?
还有其他方法可以做您想要的。 您可以使用CICheckerboardGenerator
代替背景。
或者,您也可以使用CGBitmapContext
填充的CGBitmapContext
。
首先,如果您实际上不希望矩形具有边框,则不应调用[path stroke]
。
其次,创建用于填充矩形的贝塞尔曲线路径是过大的。 您可以使用NSRectFill(r)
进行相同的NSRectFill(r)
。 此功能可能更有效,并且我怀疑不太可能在浮点数上引入舍入误差–我假设您意识到,如果需要像素精确的矩形,则浮点数不得包含小数部分。 我相信,如果视图的宽度和高度是GRIDSIZE
的倍数,并且您使用NSRectFill
,那么工件应该消失了。
第三,如果视图的宽度和高度不是GRIDSIZE
的倍数,则存在一个明显的问题,即如何绘制电路板。 如果视图的大小是固定的并且是该常数的倍数,那么这当然不是问题。 但是,如果不是这样,则首先必须澄清如何处理可能剩下的宽度或高度。 应该有边界吗? 行或列中的最后一个单元格是否应该占用其余部分? 还是应该在行或列的单元格之间平均分配它? 您可能必须接受宽度和/或高度不同的单元格。 解决问题的最佳解决方案取决于您的确切要求。
您可能还想研究其他绘制棋盘的方法,例如使用CICheckerboardGenerator
或使用CICheckerboardGenerator
创建图案颜色( [NSColor colorWithPatternImage:yourImage]
),然后用它填充整个视图。
还可能(暂时)关闭抗锯齿功能。 为此,将以下行添加到绘图方法的开头:
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
我的最后观察是关于您的一般方法。 如果您的游戏将具有更复杂的图形和动画,例如动画的棋子运动,那么使用OpenGL可能会更好。
您的方块重叠。 ix + CELLWIDTH
在循环的下一次迭代中与ix
相同。
您可以通过将笔触颜色显式设置为透明或不调用stroke
来解决此问题。
[color set];
[[NSColor clearColor] setStroke];
要么
[path fill];
// not [path stroke];
从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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.