Sunday, April 4, 2010

Sprite animation and GLTexture usage

In our last post we have talk about GLTexture files to load to our OpenGL ES screen our sprite images we have borrow for our test program. In this post we are going to try and animate our sprites we have currently available. In this case I have decided to borrow the sprites from The Legend of Zelda A Link to the Past looking, up, down, left and right. We store these image files in our Resources folder in our xCode project we have called "Test". In our last post we have modified our header file for EAGLView for OpenGL:

//

// EAGLView.h

// Test

//

// Created by Julio Cruz on 3/31/10.

// Copyright Red Fox Software 2009. All rights reserved.

//



#import

#import

#import

#import

#import "GLTexture.h"


/*

This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.

The view content is basically an EAGL surface you render your OpenGL scene into.

Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.

*/

@interface EAGLView : UIView {

@private

/* The pixel dimensions of the backbuffer */

GLint backingWidth;

GLint backingHeight;

EAGLContext *context;

/* OpenGL names for the renderbuffer and framebuffers used to render to this view */

GLuint viewRenderbuffer, viewFramebuffer;

/* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */

GLuint depthRenderbuffer;

NSTimer *animationTimer;

NSTimeInterval animationInterval;

// Create texture image.

GLTexture *diamond[6];

}


@property NSTimeInterval animationInterval;


- (void)startAnimation;

- (void)stopAnimation;

- (void)drawView;


@end


Nothing new in this source file except for GLTexture *diamond[6]; in this case we have a GLTexture array that will take about five unique images to be store in each individual array we have. After we have modified our EAGLView header file we are now really to write the functions to display the images and determine the time frame of each image to be display. In this case in our implementation file of EAGLView we have:

// Define the space to hold the global variables for the frame counter

unsigned int frameCounter;

double totalRenderingTime;


We are going to determine the first frame we have display on our OpenGL screen image and get the current time for our program later on we must determine the starting time and end time to determine our total rendering time. For example source code:


- (void)drawView {

#ifdef DEBUG

double startTime = CFAbsoluteTimeGetCurrent();

#endif

[EAGLContext setCurrentContext:context];

glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);

glViewport(0, 0, backingWidth, backingHeight);

// Draw game scene

glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);

[context presentRenderbuffer:GL_RENDERBUFFER_OES];


#ifdef DEBUG

double endTime = CFAbsoluteTimeGetCurrent();

totalRenderingTime += (endTime - startTime);

#endif

}


With CFAbsoluteTimeGetCurrent() function we can obviously determine the current time or our start time. After the game draws the current frame we must store our ending time frame. Later on we must determine the render time or the total frames that we have taken to draw to the screen. This sounds fun and easy however we must now determine when our user wants to tap our screen to see the sprites to animate. For this type of functionality we have to write a touch function:


// Detect touches of the user and animate sprite image.


#pragma mark -

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

UITouch *touch = [touches anyObject];

CGPoint point = [touch locationInView: self];

if(point.x >= 0 && point.x <= 160)

{

if(point.y >= 0 && point.y <= 480)

{

// Init images

switch (frameCounter) {

case 1:

diamond[frameCounter] = [[GLTexture alloc] initWithImage:[UIImage imageNamed:@"linklookup.png"]];

[diamond[frameCounter] drawAtPoint:CGPointMake(diamond[frameCounter].contentSize.width, diamond[frameCounter].contentSize.height)];

NSLog(@"Frame Counter: %d", frameCounter);

break;

case 2:

diamond[frameCounter] = [[GLTexture alloc] initWithImage:[UIImage imageNamed:@"linklookdown.png"]];

[diamond[frameCounter] drawAtPoint:CGPointMake(diamond[frameCounter].contentSize.width, diamond[frameCounter].contentSize.height)];

NSLog(@"Frame Counter: %d", frameCounter);

break;

case 3:

diamond[frameCounter] = [[GLTexture alloc] initWithImage:[UIImage imageNamed:@"linklookdown1.png"]];

[diamond[frameCounter] drawAtPoint:CGPointMake(diamond[frameCounter].contentSize.width, diamond[frameCounter].contentSize.height)];

NSLog(@"Frame Counter: %d", frameCounter);

break;

case 4:

diamond[frameCounter] = [[GLTexture alloc] initWithImage:[UIImage imageNamed:@"linklookleft.png"]];

[diamond[frameCounter] drawAtPoint:CGPointMake(diamond[frameCounter].contentSize.width, diamond[frameCounter].contentSize.height)];

NSLog(@"Frame Counter: %d", frameCounter);

break;

case 5:

diamond[frameCounter] = [[GLTexture alloc] initWithImage:[UIImage imageNamed:@"linklookright.png"]];

[diamond[frameCounter] drawAtPoint:CGPointMake(diamond[frameCounter].contentSize.width, diamond[frameCounter].contentSize.height)];

NSLog(@"Frame Counter: %d", frameCounter);

break;

case 6:

frameCounter = 0;

NSLog(@"Frame Counter: %d", frameCounter);

break;

default:

break;

}

}

frameCounter++;

NSLog(@"Frame Counter: %d",frameCounter);

}

}


In this function we have done several important things:

1) Touch function to detect our users taps on the screen.

2) We have specificed in what view: self.

3) We have determine the point in our view. (Left side tap.).

4) Switch statement for frameCounter.

5) If we have any frame we draw and allocate memory for this specific image being call for this frame.

6) If frame equals 6 frameCounter equals 0 to start at the first frame.

Several disadvantages I see from this implementation is that switch statement that takes 6 calls to switch statement to create a new image. Another disadvantage from this implementation function is that we have to allocate memory each time they are being call. This is not good in the perspective that when we want to animate our character we will have a different quad object for OpenGL to draw our images instead of using one quad object to draw all of our image we need to fully animate our sprite. The sprite animation will be in our second part video for next week.

Julio A. Cruz

No comments:

Post a Comment