2

我正在尝试按照教程编写 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
4

2 回答 2

0

想通了问题。

  _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); //This line should be 
                                                                     //modifying the
                                                                     //_hillTexCoords
                                                                     //array 
于 2012-06-22T00:38:57.233 回答
0

只是预感,您使用的是 cocos2d 2.0 吗?

因为您发布的代码使用 OpenGL ES 1.1 命令,并且在您使用 cocos2d 2.x 时无法(正确)工作。如果您使用的是 cocos2d 2.0,请使用 v1.x 重试。

于 2012-06-21T08:54:27.367 回答