Jonathan
Jonathan

Reputation: 2383

Lightning Lag- Cocos2d

I have several objects that "fall" from the top of the screen and when they are tapped lightning strikes them. My problem is, when one of the objects are tapped and lightning strikes my FPS goes down and the game lags.

Can someone please help me reduce this lag or lead me in the right direction? I have no clue on how to fix it. My game is finished and this is the only thing holding me back...

Here is the lightning code.

Lightning.h

//
//  Lightning.h
//  Trundle
//
//  Created by Robert Blackwood on 12/1/09.
//  Copyright 2009 Mobile Bros. All rights reserved.
//

#import "cocos2d.h"

/*! This will draw lighting and return the midpoint */
CGPoint drawLightning(CGPoint pt1, CGPoint pt2, int displace, int minDisplace, unsigned long randSeed, float width);
void drawSmoothLine(CGPoint *pos1, CGPoint *pos2, float width);
void drawSmoothPointAt(CGPoint *pos, float width);
void fillSmoothRectangle(CGRect *r, float width);

@interface Lightning : CCNode <CCRGBAProtocol>
{
    CGPoint _strikePoint;
    CGPoint _strikePoint2;
    CGPoint _strikePoint3;

    ccColor3B   _color;
    GLubyte     _opacity;
    BOOL        _split;
    BOOL        _glow;

    int _displacement;
    int _minDisplacement;
    float _lighteningWidth;

    unsigned long _seed;
}

@property (readwrite, assign) CGPoint strikePoint;
@property (readwrite, assign) CGPoint strikePoint2;
@property (readwrite, assign) CGPoint strikePoint3;
@property (readwrite, assign) ccColor3B color;
@property (readwrite, assign) GLubyte opacity;
@property (readwrite, assign) BOOL split;
@property (readwrite, assign) BOOL glow;
@property (readwrite, assign) int displacement;
@property (readwrite, assign) int minDisplacement;
@property (readwrite, assign) float lighteningWidth;
@property (readwrite, assign) unsigned long seed;

+(id) lightningWithStrikePoint:(CGPoint)strikePoint strikePoint2:(CGPoint)strikePoint2;

-(id) initWithStrikePoint:(CGPoint)strikePoint strikePoint2:(CGPoint)strikePoint2;

-(void) strikeRandom;
-(void) fade;

@end

Lightning.m

//
//  Lightning.m
//  Trundle
//
//  Created by Robert Blackwood on 12/1/09.
//  Copyright 2009 Mobile Bros. All rights reserved.
//

#import "Lightning.h"

@implementation Lightning

@synthesize strikePoint = _strikePoint;
@synthesize strikePoint2 = _strikePoint2;
@synthesize strikePoint3 = _strikePoint3;
@synthesize color = _color;
@synthesize opacity = _opacity;
@synthesize displacement = _displacement;
@synthesize minDisplacement = _minDisplacement;
@synthesize lighteningWidth = _lighteningWidth;
@synthesize seed = _seed;
@synthesize split = _split;
@synthesize glow = _glow;

+(id) lightningWithStrikePoint:(CGPoint)strikePoint strikePoint2:(CGPoint)strikePoint2
{
    return [[[self alloc] initWithStrikePoint:strikePoint strikePoint2:strikePoint2] autorelease];
}

-(id) initWithStrikePoint:(CGPoint)strikePoint strikePoint2:(CGPoint)strikePoint2
{
    if ((self = [super init]))
    {
        _strikePoint = strikePoint;
        _strikePoint2 = ccp(0, 0);
        _strikePoint3 = strikePoint2;

        _color = ccc3(255, 190, 255);

        //random style
        _displacement = 100 + CCRANDOM_0_1() * 200;
        _minDisplacement = 4 + CCRANDOM_0_1() * 10;
        _lighteningWidth = 2.0f;
        _split = YES;
        _glow = YES;

        [self strikeRandom];
    }

    return self;
}

-(void) draw
{
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glColor4ub(_color.r, _color.g, _color.b, _opacity);

    drawLightning(_strikePoint3, _strikePoint, _displacement, _minDisplacement, _seed, _lighteningWidth);

    if (_glow)
    {
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        glColor4ub(50, 0, 255, _opacity);
        drawLightning(_strikePoint3, _strikePoint, _displacement, _minDisplacement, _seed, 7);
    }

    if (_opacity != 255)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    if (_opacity != 255)
        glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);

    glColor4f(1.0, 1.0, 1.0, 1.0);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);
}

-(void) strikeRandom
{
    _glow = YES;
    _seed = rand();
    [self fade];
}

- (void) removeLightning {
    self.visible = NO;
}

- (void) fade
{
    self.visible = YES;
    self.opacity = 255;

    [self runAction:[CCSequence actions: 
                    // [DelayTime actionWithDuration:1.0],
                     [CCShow action],
                     [CCFadeOut actionWithDuration:0.5],
                     [CCCallFunc actionWithTarget:self selector:@selector(removeLightning)],
                     nil]];
}

-(void)dealloc
{
    [super dealloc];
}

@end

int getNextRandom(unsigned long *seed)
{
    //taken off a linux site (linux.die.net)
    (*seed) = (*seed) * 1103515245 + 12345;
    return ((unsigned)((*seed)/65536)%32768);
}

CGPoint drawLightning(CGPoint pt1, CGPoint pt2, int displace, int minDisplace, unsigned long randSeed, float width)
{   
    CGPoint mid = ccpMult(ccpAdd(pt1,pt2), 0.5f);

    if (displace < minDisplace)
    {
        //ccDrawLine(pt1, pt2);
        drawSmoothLine(&pt1, &pt2, width);
        drawSmoothPointAt(&mid, width);
    }
    else
    {
        int r = getNextRandom(&randSeed);
        mid.x += (((r % 101)/100.0)-.5)*displace;
        r = getNextRandom(&randSeed);
        mid.y += (((r % 101)/100.0)-.5)*displace;

        drawLightning(pt1,mid,displace/2,minDisplace,randSeed,width);
        drawLightning(pt2,mid,displace/2,minDisplace,randSeed,width);
    }

    return mid;
} 

void drawSmoothLine(CGPoint *pos1, CGPoint *pos2, float width)
{
    GLfloat lineVertices[12], currentColor[4]; 
    GLint   red, green, blue, alpha;
    CGPoint dir, tan;

    dir.x = pos2->x - pos1->x;
    dir.y = pos2->y - pos1->y;
    float len = sqrtf(dir.x * dir.x + dir.y * dir.y);
    if(len < 0.00001)
        return;
    dir.x = dir.x / len;
    dir.y = dir.y / len;
    tan.x = -width * dir.y;
    tan.y = width * dir.x;

    lineVertices[0] = pos1->x + tan.x;
    lineVertices[1] = pos1->y + tan.y;
    lineVertices[2] = pos2->x + tan.x;
    lineVertices[3] = pos2->y + tan.y;
    lineVertices[4] = pos1->x;
    lineVertices[5] = pos1->y;
    lineVertices[6] = pos2->x;
    lineVertices[7] = pos2->y;
    lineVertices[8] = pos1->x - tan.x;
    lineVertices[9] = pos1->y - tan.y;
    lineVertices[10] = pos2->x - tan.x;
    lineVertices[11] = pos2->y - tan.y;

    glGetFloatv(GL_CURRENT_COLOR, currentColor);
    red = 255.0 * currentColor[0];
    green = 255.0 * currentColor[1];
    blue = 255.0 * currentColor[2];
    alpha = 255.0 * currentColor[3];

    const GLubyte lineColors[] = {
        red, green, blue, 0,
        red, green, blue, 0,
        red, green, blue, alpha,
        red, green, blue, alpha,
        red, green, blue, 0,
        red, green, blue, 0,
    };

    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glVertexPointer(2, GL_FLOAT, 0, lineVertices);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, lineColors);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);

    glDisableClientState(GL_COLOR_ARRAY);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);
}

void drawSmoothPointAt(CGPoint *position, float width)
{
    GLfloat pntVertices[2*6], currentColor[4]; 
    GLint   red, green, blue, alpha;

    pntVertices[0] = position->x;
    pntVertices[1] = position->y;
    pntVertices[2] = position->x - width;
    pntVertices[3] = position->y - width;
    pntVertices[4] = position->x - width;
    pntVertices[5] = position->y + width;
    pntVertices[6] = position->x + width;
    pntVertices[7] = position->y + width;
    pntVertices[8] = position->x + width;
    pntVertices[9] = position->y - width;
    pntVertices[10] = position->x - width;
    pntVertices[11] = position->y - width;

    glGetFloatv(GL_CURRENT_COLOR, currentColor);
    red = 255.0 * currentColor[0];
    green = 255.0 * currentColor[1];
    blue = 255.0 * currentColor[2];
    alpha = 255.0 * currentColor[3];

    const GLubyte pntColors[] = {
        red, green, blue, alpha,
        red, green, blue, 0,
        red, green, blue, 0,
        red, green, blue, 0,
        red, green, blue, 0,
        red, green, blue, 0,
    };

    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glVertexPointer(2, GL_FLOAT, 0, pntVertices);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, pntColors);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

    glDisableClientState(GL_COLOR_ARRAY);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnable(GL_TEXTURE_2D);
}

Upvotes: 1

Views: 404

Answers (2)

johnbakers
johnbakers

Reputation: 24750

Your FPS will dramatically improve if you import your lightning as PNG images in a batch node texture. Assuming you have multiple lightning images firing from different directions simultaneously, this will only result in one total call to OpenGL, and that call will not have drawing logic since the images will have already been created outside the app.

Upvotes: 1

skytz
skytz

Reputation: 2201

you are doing WAY too many calculations to get the effect you want

i dont want to make you rewrite your code..but look into bezier curve through point

here is what i mean (set the tension to 0.5 or smth..to get lightning-like effect)

do that..or just make a bunch or random generated images (lightning) and just put them on top of the image to get the lightning effect..what you're doing is too expensive for a small device

Upvotes: 1

Related Questions