Tiny Wings タイプのゲームを作成するには、このチュートリアルに従ってください。
私はそれの終わりに立ち往生しています。なだらかな丘の代わりに、見栄えの悪い三角形の描画が表示されます。以下にいくつかのスクリーンショットを投稿しました。
チュートリアルの時点で、デバッガーで適切に表示するためにコメントを解除することが言及されています。私はそれをしました、そしてそれはまだこれをやっています。これは単なるシミュレーターなのか、それともどこかを台無しにしたのでしょうか。何が起こっていても、定期的にレンダリングされているので、コサイン関数は数学的に機能しているに違いないと思いますが、それでもこの動作は説明できません。基本的に、私は困惑しています。
これが私が使用しているコードです
HelloWorldLayer.h
#import "cocos2d.h"
#import "Terrain.h"
/*#import "Box2D.h"
#import "GLES-Render.h"*/
// HelloWorldLayer
@interface HelloWorldLayer : CCLayer
{
CCSprite *_background;
Terrain *_terrain;
/*b2World* world;
GLESDebugDraw *m_debugDraw;*/
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
// adds a new sprite at a given coordinate
//-(void) addNewSpriteWithCoords:(CGPoint)p;
@end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
//Pixel to metres ratio. Box2D uses metres as the unit for measurement.
//This ratio defines how many pixels correspond to 1 Box2D "metre"
//Box2D is optimized for objects of 1x1 metre therefore it makes sense
//to define the ratio so that your most common object type is 1x1 metre.
#define PTM_RATIO 32
// enums that will be used as tags
/*enum {
kTagTileMap = 1,
kTagBatchNode = 1,
kTagAnimation1 = 1,
};*/
// HelloWorldLayer implementation
@implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(CCSprite *)spriteWithColor:(ccColor4F)bgColor textureSize:(float)textureSize {
// 1: Create new CCRenderTexture
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:textureSize height:textureSize];
// 2: Call CCRenderTexture:begin
[rt beginWithClear:bgColor.r g:bgColor.g b:bgColor.b a:bgColor.a];
//Add Gradient to image
/*The basic idea is we’ll draw a black rectangle on top of the texture, but it will be completely transparent up top, and opaque at the bottom. This will keep the top untouched, but gradually darken the image going down*/
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
float gradientAlpha;
CGPoint vertices[4];
ccColor4F colors[4];
int nVertices = 0;
vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
vertices[nVertices] = CGPointMake(textureSize, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(0, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
vertices[nVertices] = CGPointMake(textureSize, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
// 3: Draw into the texture
// We'll add this later
CCSprite *noise = [CCSprite spriteWithFile:@"Noise.png"];
[noise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
noise.position = ccp(textureSize/2, textureSize/2);
[noise visit];
// 4: Call CCRenderTexture:end
[rt end];
// 5: Create a new Sprite from the texture
return [CCSprite spriteWithTexture:rt.sprite.texture];
}
-(CCSprite *)stripedSpriteWithColor1:(ccColor4F)c1 color2:(ccColor4F)c2
textureSize:(float)textureSize stripes:(int)nStripes {
// 1:Create new CCRenderTexture
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:textureSize height:textureSize];
// 2: Call CCRenderTexture:begin
[rt beginWithClear:c1.r g:c1.g b:c1.b a:c1.a];
// 3: Draw into the texture
// Layer 1: Stripes
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
CGPoint vertices[nStripes*6];
int nVertices = 0;
float x1 = -textureSize;
float x2;
float y1 = textureSize;
float y2 = 0;
float dx = textureSize/ nStripes*2;
float stripeWidth = dx/2;
for (int i = 0; i<nStripes; i++) {
x2 = x1 +textureSize;
vertices[nVertices++]=CGPointMake(x1, y1);
vertices[nVertices++]=CGPointMake(x1+stripeWidth, y1);
vertices[nVertices++]=CGPointMake(x2, y2);
vertices[nVertices++]= vertices[nVertices-2];
vertices[nVertices++]= vertices[nVertices-2];
vertices[nVertices++]=CGPointMake(x2+stripeWidth, y2);
x1 += dx;
}
glColor4f(c2.r, c2.g, c2.b, c2.a);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)nVertices);
// layer 2: gradient
glEnableClientState(GL_COLOR_ARRAY);
float gradientAlpha = 0.7;
ccColor4F colors[4];
nVertices = 0;
vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0 };
vertices[nVertices] = CGPointMake(textureSize, 0);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(0, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
vertices[nVertices] = CGPointMake(textureSize, textureSize);
colors[nVertices++] = (ccColor4F){0, 0, 0, gradientAlpha};
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, colors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);
// layer 3: top highlight
float borderWidth = textureSize/16;
float borderAlpha = 0.3f;
nVertices = 0;
vertices[nVertices] = CGPointMake(0, 0);
colors[nVertices++] = (ccColor4F){1,1,1,borderAlpha};
vertices[nVertices] = CGPointMake(textureSize, 0);
colors[nVertices++] = (ccColor4F){1,1,1,borderAlpha};
vertices[nVertices] = CGPointMake(0, borderWidth);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
vertices[nVertices] = CGPointMake(textureSize, borderWidth);
colors[nVertices++] = (ccColor4F){0, 0, 0, 0};
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, colors);
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)nVertices);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
// Layer 2: Noise
CCSprite *noise = [CCSprite spriteWithFile:@"Noise.png"];
[noise setBlendFunc:(ccBlendFunc){GL_DST_COLOR, GL_ZERO}];
noise.position = ccp(textureSize/2, textureSize/2);
[noise visit];
// 4: Call CCRenderTexture:end
[rt end];
// 5: Create a new Sprite from the texture
return [CCSprite spriteWithTexture:rt.sprite.texture];
}
-(ccColor4F)randomBrightColor {
while (true) {
float requiredBrightness = 192;
ccColor4B randomColor = ccc4(arc4random() % 255,
arc4random() % 255,
arc4random() % 255,
255);
if (randomColor.r > requiredBrightness ||
randomColor.g > requiredBrightness ||
randomColor.b > requiredBrightness) {
return ccc4FFromccc4B(randomColor);
}
}
}
-(void)genBackground {
[_background removeFromParentAndCleanup:YES];
ccColor4F bgColor = [self randomBrightColor];
/*new code*/
//ccColor4F color2 = [self randomBrightColor];
/*new code*/
_background = [self spriteWithColor:bgColor textureSize:512];
/*new code*/
// int nStripes = ((arc4random() % 4) + 1) * 2;
//_background = [self stripedSpriteWithColor1:bgColor color2:color2 textureSize:512 stripes:nStripes];
//self.scale = 0.5;
/*new code*/
CGSize winSize = [CCDirector sharedDirector].winSize;
_background.position = ccp(winSize.width/2,winSize.height/2);
ccTexParams tp = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
[_background.texture setTexParameters:&tp];
[self addChild:_background z:-1];
ccColor4F color3 = [self randomBrightColor];
ccColor4F color4 = [self randomBrightColor];
CCSprite *stripes = [self stripedSpriteWithColor1:color3 color2:color4 textureSize:512 stripes:4];
ccTexParams tp2 = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_CLAMP_TO_EDGE};
[stripes.texture setTexParameters:&tp2];
_terrain.stripes = stripes;
/*The important part is the texture parameters:
GL_LINEAR is a fancy way of saying “when displaying the texture at a smaller or larger scale than the original size, take a weighted average of the nearby pixels.”
GL_REPEAT is a fancy way of saying “if you try to index a texture at a coordinate outside the texture bounds, put what would be there if the texture were to continuously tile.”*/
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
_terrain = [Terrain node];
[self addChild:_terrain z:1];
[self genBackground];
self.isTouchEnabled = YES;
[self scheduleUpdate];
}
self.scale = 1.0;
return self;
}
-(void)update:(ccTime)dt {
float PIXELS_PER_SECOND = 100;
static float offset = 0;
offset += PIXELS_PER_SECOND * dt;
CGSize textureSize = _background.textureRect.size;
[_background setTextureRect:CGRectMake(offset, 0, textureSize.width, textureSize.height)];
[_terrain setOffsetX:offset];
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self genBackground];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
/*delete world;
world = NULL;
delete m_debugDraw;*/
// don't forget to call "super dealloc"
[super dealloc];
}
@end
地形.h
#import "CCNode.h"
#import "cocos2d.h"
@class HelloWorldLayer;
#define kMaxHillKeyPoints 1000
#define kHillSegmentWidth 10
#define kMaxHillVertices 4000
#define kMaxBorderVertices 800
@interface Terrain : CCNode {
int _offsetX;
CGPoint _hillKeyPoints[kMaxHillKeyPoints];
CCSprite *_stripes;
int _fromKeyPointI;
int _toKeyPointI;
int _nHillVertices;
CGPoint _hillVertices[kMaxHillVertices];
CGPoint _hillTexCoords[kMaxHillVertices];
int _nBorderVertices;
CGPoint _borderVertices[kMaxBorderVertices];
}
@property (retain) CCSprite * stripes;
-(void)setOffsetX:(float)newOffsetX;
@end
地形.m
#import "Terrain.h"
#import "HelloWorldLayer.h"
@implementation Terrain
@synthesize stripes = _stripes;
-(void)generateHills {
/*
The strategy in this algorithm is the following:
Increment x-axis in the range of 160 + a random number between 0-40
Increment y-axis in the range of 60 + a random number between 0-40
Except: reverse the y-axis offset every other time.
Don’t let the y value get too close to the top or bottom (paddingTop, paddingBottom)
Start offscreen to the left, and hardcode the second point to (0, winSize.height/2), so there’s a hill coming up from the left offscreen.*/
CGSize winSize = [CCDirector sharedDirector].winSize;
float minDX = 160;
float minDY = 60;
int rangeDX = 80;
int rangeDY= 40;
float x = -minDX;
float y = winSize.height/2 - minDY;
float dy, ny;
float sign = 1;// +1 - going up, -1 - going down
float paddingTop = 20;
float paddingBottom = 20;
for (int i=0; i<kMaxHillKeyPoints; i++) {
_hillKeyPoints[i] = CGPointMake(x, y);
if (i == 0) {
x = 0;
y = winSize.height/2;
} else {
x+=rand()%rangeDX+minDX;
while (true) {
dy = rand()%rangeDY + minDY;
ny = y + dy*sign;
if (ny < winSize.height - paddingTop && ny > paddingBottom) {
break;
}
}
y = ny;
}
sign *= -1;
}
/*float x = 0;
float y = winSize.width/2;
for (int i = 0; i<kMaxHillKeyPoints; ++i) {
_hillKeyPoints[i] = CGPointMake(x, y);
x += winSize.width/2;
y = random() % (int) winSize.height;
}*/
}
-(void)resetHillVertices {
CGSize winSize = [CCDirector sharedDirector].winSize;
static int prevFromKeyPointI = -1;
static int prevToKeyPointI = -1;
// key points interval for drawing
// key points interval for drawing
while (_hillKeyPoints[_fromKeyPointI+1].x < _offsetX-winSize.width/8/self.scale) {
_fromKeyPointI++;
}
while (_hillKeyPoints[_toKeyPointI].x < _offsetX+winSize.width*9/8/self.scale) {
_toKeyPointI++;
}
if (prevFromKeyPointI != _fromKeyPointI || prevToKeyPointI != _toKeyPointI) {
// vertices for visible area
_nHillVertices = 0;
_nBorderVertices =0;
CGPoint p0, p1, pt0, pt1;
p0 = _hillKeyPoints[_fromKeyPointI];
for (int i = _fromKeyPointI+1; i<_toKeyPointI+1; i++) {
p1 = _hillKeyPoints[i];
// triangle strip between p0 and p1
int hSegments = floorf((p1.x-p0.x)/kHillSegmentWidth);
float dx = (p1.x - p0.x)/hSegments;
float da = M_PI / hSegments;
float ymid = (p0.y + p1.y)/2;
float ampl = (p0.y - p1.y)/2;
pt0 = p0;
_borderVertices[_nBorderVertices++] = pt0;
for (int j=1; j<hSegments+1; j++) {
pt1.x = p0.x + j* dx;
pt1.y = ymid +ampl * cosf(da*j);
_borderVertices[_nBorderVertices++] = pt1;
_hillVertices[_nHillVertices] = CGPointMake(pt0.x, 0);
_hillTexCoords[_nHillVertices++] = CGPointMake(pt0.x/512, 1.0f);
_hillVertices[_nHillVertices] = CGPointMake(pt1.x, 0);
_hillTexCoords[_nHillVertices++] = CGPointMake(pt1.x/512, 1.0f);
_hillVertices[_nHillVertices] = CGPointMake(pt0.x, pt0.y);
_hillTexCoords[_nHillVertices++] = CGPointMake(pt0.x/512, 0);
_hillVertices[_nHillVertices] = CGPointMake(pt1.x, pt1.y);
_hillVertices[_nHillVertices++] = CGPointMake(pt1.x/512, 0);
pt0 = pt1;
}
p0 = p1;
}
prevFromKeyPointI = _fromKeyPointI;
prevToKeyPointI = _toKeyPointI;
}
}
-(id)init {
if ((self = [super init])) {
[self generateHills];
}
[self resetHillVertices];
return self;
}
-(void) draw {
glBindTexture(GL_TEXTURE_2D, _stripes.texture.name);
glDisableClientState(GL_COLOR_ARRAY);
glColor4f(1, 1, 1, 1);
glVertexPointer(2, GL_FLOAT, 0, _hillVertices);
glTexCoordPointer(2, GL_FLOAT, 0, _hillTexCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)_nHillVertices);
// glEnableClientState(GL_COLOR_ARRAY);
for (int i= MAX(_fromKeyPointI, 1); i <= _toKeyPointI; ++i) {
glColor4f(1.0, 0, 0, 1.0);
//ccDrawLine(_hillKeyPoints[i-1], _hillKeyPoints[i]);
glColor4f(1.0, 1.0, 1.0, 1.0);
CGPoint p0 = _hillKeyPoints[i-1];
CGPoint p1 = _hillKeyPoints[i];
int hSegments = floorf((p1.x-p0.x)/kHillSegmentWidth);
float dx = (p1.x-p0.x)/hSegments;
float da = M_PI /hSegments;
float ymid = (p0.y + p1.y)/2;
float ampl = (p0.y - p1.y)/2;
CGPoint pt0, pt1;
pt0 = p0;
for (int j= 0; j<hSegments+1; ++j) {
pt1.x = p0.x +j*dx;
pt1.y = ymid + ampl * cosf(da*j);
//ccDrawLine(pt0, pt1);
pt0 = pt1;
}
}
}
-(void)setOffsetX:(float)newOffsetX {
_offsetX = newOffsetX;
self.position = CGPointMake(-_offsetX*self.scale, 0);
[self resetHillVertices];
}
-(void) dealloc {
[_stripes release];
_stripes = NULL;
[super dealloc];
}
@end