아이폰어플개발정보2010. 10. 23. 23:47
[아이폰 앱 개발] subview들 루프돌며 찾기.. subview들에 tag 속성을 준경우

Detecting Subviews

You can loop through subviews of an existing view. This works especially well if you use the "tag" property on your views.
for (UIImageView *anImage in [self.view subviews]) { if (anImage.tag == 1) { // do something } }
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 10. 23. 18:46
[아이폰 앱 개발] iphone crash log 위치 on the MAC 및 로그까는 symbolicatecrash프로그램 및 설치하기 명령어

IPhone Crash Logs

Sometimes programs crash. This annoys users and developers alike. Users are frustrated because they cannot use crashing software, developers are frustrated because they have to hunt bugs instead of doing something creative and rewarding. How do we communicate if an iPhone application crashes?

I’ll start with a disclaimer. I’m not sure whether the information provided in this post is covered by iPhone Developer Program NDA or not. If it is, the post will be removed. Secondly, this post is a result of googling, so I haven’t invented anything new here.

Working with crash logs typically involves certain interaction between developers and users, unless they are automagically sent to the developer. First of all, the user should get the crash log and send it to the developer, who should examine it, find the bug and fix it.

iPhone OS and Mac OS X are remarkably similar architectures. Both store crash logs to help identify crashing bugs. The difference between the two is how users retrieve them. On Mac OS X every user has unrestricted access to crash logs related to the applications she runs. The iPhone does not even have a file browser. What to do? iTunes comes to the rescue.

Whenever you synchronize your iPhone or iPod Touch, all the crash logs are transferred to your computer. Here are their locations:

  • Mac OS X:~/Library/Logs/CrashReporter/MobileDevice/<DEVICE_NAME>
  • Windows XPC:\Documents and Settings\<USERNAME>\Application Data\Apple computer\Logs\CrashReporter/<DEVICE_NAME>
  • Windows VistaC:\Users\<USERNAME>\AppData\Roaming\Apple computer\Logs\CrashReporter/MobileDevice/<DEVICE_NAME>

The log file names start with application name and have the extension “crash”. They are just plain text files and can be sent by e-mail in original or zipped form, or even copy-pasted into your e-mail program.

The second part is trickier. Both Apple and common sense suggest that all AppStore binaries are shipped with stripped symbols. If you ever saw a crash log like this, read on:


까보면 아래처럼 나옮.. 저 밑에 어플리케이션하나 설치하면 크래쉬로그를 인간이 이해할 수 있는 

메모리에서 돌아가던 콘트롤명이나 생성한 객체들이나 이벤트들이 보이게됨.


Thread 0 Crashed:
0   libobjc.A.dylib           0x300c87ec 0x300bb000 + 55276
1   MobileLines               0x00006434 0x1000 + 21556
2   MobileLines               0x000064c2 0x1000 + 21698
3   UIKit                     0x30a740ac 0x30a54000 + 131244
4   UIKit                     0x30a66110 0x30a54000 + 74000
5   UIKit                     0x30a6565c 0x30a54000 + 71260
6   GraphicsServices          0x3169b0b4 0x31696000 + 20660
7   GraphicsServices          0x3169d818 0x31696000 + 30744
8   IOMobileFramebuffer       0x31f3e8f8 0x31f3d000 + 6392
9   com.apple.framework.IOKit 0x30f342b8 0x30f30000 + 17080
10  CoreFoundation            0x3025ced4 0x30229000 + 212692
11  CoreFoundation            0x3025bed6 0x30229000 + 208598
12  CoreFoundation            0x3025b584 0x30229000 + 206212
13  GraphicsServices          0x316998e4 0x31696000 + 14564
14  UIKit                     0x30a5e308 0x30a54000 + 41736
15  UIKit                     0x30a671dc 0x30a54000 + 78300
16  MobileLines               0x00002090 0x1000 + 4240
17  MobileLines               0x0000202c 0x1000 + 4140

In a nutshell, it contains function addresses and offsets instead of function names and line numbers. The structure is obvious, but, to be honest, I don’t know what “MobileLines 0×00006434 0×1000 + 21556″ is, even though I have all the source code. Thanks to Apple Developer Tools and to Craig Hockenberry who wrote about it, we have a perfect solution called symbolicatecrash.


위의 크래쉬로그를 가독성있게 분석할 수 있도록하는 툴


/usr/local/bin/으로 위의 프로그램 옮기고

$ sudo cp /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneRemoteDevice.xcodeplugin/Contents/Resources/symbolicatecrash /usr/local/bin/

위의 명령어로 설치하고

$ symbolicatecrash report.crash MobileLines.app.dSYM > report-with-symbols.crash

통해  크래쉬로그를 가독성있도록 바꿈


I copied it to /usr/local/bin/ so that I can run it whenever I want without trying to remember its original location (you may prefer a symbolic link):
$ sudo cp /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneRemoteDevice.xcodeplugin/Contents/Resources/symbolicatecrash /usr/local/bin/

Running this script with the -h option provides the minimal help:

$ symbolicatecrash -h
usage:

    symbolicatecrash [-Ah] LOGFILE [SYMBOL_PATH ...]

    Symbolicates a crashdump LOGFILE which may be "-" to refer
  to stdin. By default, all heuristics will be employed
  in an attempt to symbolicate all addresses. Additional
  symbol files can be found under specified directories.

Options:
    -A  Only symbolicate the application, not libraries
    -h  Display this message
    -v  Verbose

To add symbols to the crash log you need the dSYM file generated by the linker when you compiled your application for AppStore. In other words, when you build for AppStore you should keep the dSYM package in a safe place backed up by Time Machine. This is very important. You should keep a copy of the dSYM for each version of your application ever shipped. If you have the package, translating code offsets to function names with line numbers has never been easier:

$ symbolicatecrash report.crash MobileLines.app.dSYM > report-with-symbols.crash

Here is the result:


Thread 0 Crashed:
0   libobjc.A.dylib           0x300c87ec objc_msgSend + 20
1   MobileLines               0x00006434 -[BoardView setSelectedPiece:] (BoardView.m:321)
2   MobileLines               0x000064c2 -[BoardView touchesBegan:withEvent:] (BoardView.m:349)
3   UIKit                     0x30a740ac -[UIWindow sendEvent:] + 264
4   UIKit                     0x30a66110 -[UIApplication sendEvent:] + 248
5   UIKit                     0x30a6565c _UIApplicationHandleEvent + 4088
6   GraphicsServices          0x3169b0b4 PurpleEventCallback + 428
7   GraphicsServices          0x3169d818 HeartbeatVBLCallback + 152
8   IOMobileFramebuffer       0x31f3e8f8 IOMobileFramebufferNotifyFunc + 124
9   com.apple.framework.IOKit 0x30f342b8 IODispatchCalloutFromCFMessage + 304
10  CoreFoundation            0x3025ced4 __CFMachPortPerform + 72
11  CoreFoundation            0x3025bed6 CFRunLoopRunSpecific + 2364
12  CoreFoundation            0x3025b584 CFRunLoopRunInMode + 44
13  GraphicsServices          0x316998e4 GSEventRunModal + 268
14  UIKit                     0x30a5e308 -[UIApplication _run] + 404
15  UIKit                     0x30a671dc UIApplicationMain + 1064
16  MobileLines               0x00002090 main (main.m:16)
17  MobileLines               0x0000202c start + 44

Now, this is much better. Happy debugging!

Other useful references:

http://www.anoshkin.net/blog/2008/09/09/iphone-crash-logs/
    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 23. 14:51
    [아이폰 앱 개발] warning: X may not reposnd to Y 관련
    Originally Posted by occular 
    I'm just wondering what the usual way is of fixing "warning: X may not reposnd to Y" warnings?

    I can see what the problem is, just not sure of the best way to fix it...
    This is a method in a controller of mine that subclasses UIViewController:

    - (void)viewWillAppearBOOL)animated {
    [[self view] setupAnimation];
    }

    The '[self view]' gives us the "UIView view" field inherited from UIViewController, and the compiler of course can't tell that the UIView in question responds to the setupAnimation message.

    So what is the best way to fix this situation?
    Would adding a selector check be the way forward?

    thanks!
    Ok, so it turns out that plain old casting is fine as the solution:

    [(MyView*)[self view] setupAnimation];

    For some reason I got it into my head that casting wasn't the objective c 'way' or something, but apparently that is not the case!
    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 23. 09:49
    [아이폰 앱 개발] good sample)full screen camera
    1. 1: Create a Normal View Based Application  
    2.   
    3. 2: Drag in "BTLFullScreenCameraController" *.h and *.m files into Xcode.  
    4.   
    5. 3: In the Header file, implement this:  
    6. #import "BTLFullScreenCameraController.h"  
    7.   
    8. 4: Add in the delegations <UIImagePickerControllerDelegate, UINavigationControllerDelegate>  
    9. {  
    10.     UIView *BaseView;                      //Base View that everything else adds to.  
    11.     BTLFullScreenCameraController *camera; //The Magic  
    12.     UIImageView *LCARS_Frame;              //The ImageView that frames the whole camera [LCARS Frame]  
    13.     UILabel *label;                        //Labels and more labels :D [Possibly the information tags]  
    14. }  
    15. @property (nonatomic, retain) UIView *BaseView;  
    16. @property (nonatomic, retain) BTLFullScreenCameraController *camera;  
    17. @property (nonatomic, retain) UIImageView *LCARS_Frame;  
    18. @property (nonatomic, retain) UILabel *label;  
    19.   
    20. /////////////////////////  
    21. //Camera Initialization  
    22. - (void)initCamera;  
    23. - (void)startCamera;  
    24. /////////////////////////  
    25.   
    26. 5: In the *.m File:  
    27. On the of the @implementation file, add this:  
    28. #define OVERLAY_ALPHA 0.50f  
    29.   
    30. @synthesize BaseView;  
    31. @synthesize camera;  
    32. @synthesize LCARS_Frame;  
    33. @synthesize label;  
    34.   
    35. - (void)loadView  
    36. {  
    37.     self.navigationController.toolbarHidden = YES;  
    38.     self.navigationController.navigationBarHidden = YES;  
    39.     [UIApplication sharedApplication].statusBarHidden = YES; //This code remove the time and battery indicator top bar.  
    40.       
    41.     self.BaseView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; //You need to Rect the BaseView to take up the battery indicator's space.  
    42.     self.BaseView.opaque = NO;            //This somehow affects the LCARS Frame image that will be super imposed on top by allow the next line to work.  
    43.     self.BaseView.alpha = OVERLAY_ALPHA;  //This line can only work after the previous line.  
    44.       
    45.     //Add Image First  
    46.     LCARS_Frame = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"binocs.png"]] autorelease];  
    47.     [self.BaseView addSubview:LCARS_Frame];  
    48.       
    49.     //Then Label, else label will be under the opacity of the image and get darker.  
    50.     label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];  
    51.     label.text = @"AR Up";  
    52.     label.textAlignment = UITextAlignmentCenter;  
    53.     label.adjustsFontSizeToFitWidth = YES;  
    54.     label.textColor = [UIColor redColor];  
    55.     label.backgroundColor = [UIColor darkGrayColor];  
    56.     label.shadowOffset = CGSizeMake(0, -1);    
    57.     label.shadowColor = [UIColor blackColor];    
    58.     [self.BaseView addSubview:label];  
    59.       
    60.       
    61.     self.view = self.BaseView; //Set BaseView as the default view.   
    62.       
    63.     [super viewDidLoad];  
    64. }  
    65.   
    66. ////////////////////////////////////////////////////////////////////////////////////////////////////  
    67. //Just copy and paste this code, it will work.  
    68. -(void) viewDidAppear:(BOOL)animated  
    69. {  
    70.     [self initCamera];  
    71.     [self startCamera];  
    72. }  
    73.   
    74. - (void) initCamera {    
    75.     if ([BTLFullScreenCameraController isAvailable]) {    
    76.           
    77.         NSLog(@"Initializing camera.");  
    78.         BTLFullScreenCameraController *tmpCamera = [[BTLFullScreenCameraController alloc] init];  
    79.         [tmpCamera.view setBackgroundColor:[UIColor blueColor]];  
    80.         [tmpCamera setCameraOverlayView:self.view];  
    81.         tmpCamera.overlayController = self;  
    82.          
    83. #ifdef BTL_INCLUDE_IMAGE_SHARING  
    84.         BTLImageShareController *shareController = [[BTLImageShareController alloc] init];  
    85.         shareController.delegate = self;  
    86.         [self.view addSubview:shareController.view];  
    87.         tmpCamera.shareController = shareController;          
    88. #endif  
    89.           
    90.         self.camera = tmpCamera;  
    91.         [tmpCamera release];  
    92.     } else {  
    93.         NSLog(@"Camera not available.");  
    94.     }  
    95. }  
    96.   
    97. - (void)startCamera {  
    98.     // TODO: figure out why simply setting the view is not working  
    99.     // since the modal view is not as desirable  
    100.       
    101.     // This isn't working but should:  
    102.     //self.view = self.camera.view;  
    103.       
    104.     // Modal view always works, but it's harder to work with.  
    105.     [self.camera displayModalWithController:self animated:YES];  
    106. }  
    107. //////////////////////////////////////////////////////////////////////////////////////////////////// 
    http://www.iphonedevforums.com/forum/sdk-coding-help/2415-code-full-screen-camera-step-bystep-idiot-prove.html
    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 23. 06:47
    [아이폰 앱 개발] UIView 높이 폭변경
     self.view.bounds.size.width
    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 23. 03:40
    [아이폰 앱 개발] save it as a file after downloading image

    Download an Image and Save it as PNG or JPEG in iPhone SDK

    Here is a quick example to save an image as JPEG or PNG. In this tutorial, I’m getting the image from the Internet then I’m saving it as JPEG and PNG.

    Key points:

    • NSData to retrieve the image from the URL
    • NSDocumentDirectory to find Document folder’s Path
    • UIImagePNGRepresentation to save it as PNG
    • UIImageJPEGRepresentation to save it as JPEG
    
            NSLog(@"Downloading...");
            // Get an image from the URL below
            UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.objectgraph.com/images/og_logo.png"]]];
     
            NSLog(@"%f,%f",image.size.width,image.size.height);
     
            // Let's save the file into Document folder.
            // You can also change this to your desktop for testing. (e.g. /Users/kiichi/Desktop/)
            // NSString *deskTopDir = @"/Users/kiichi/Desktop";
     
            NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
     
            // If you go to the folder below, you will find those pictures
            NSLog(@"%@",docDir);
     
            NSLog(@"saving png");
            NSString *pngFilePath = [NSString stringWithFormat:@"%@/test.png",docDir];
            NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(image)];
            [data1 writeToFile:pngFilePath atomically:YES];
     
            NSLog(@"saving jpeg");
            NSString *jpegFilePath = [NSString stringWithFormat:@"%@/test.jpeg",docDir];
            NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];//1.0f = 100% quality
            [data2 writeToFile:jpegFilePath atomically:YES];
     
            NSLog(@"saving image done");
     
            [image release];
    

    Download Sample XCode Project from here


    http://blog.objectgraph.com/index.php/2010/04/05/download-an-image-and-save-it-as-png-or-jpeg-in-iphone-sdk/

    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 22. 23:03
    [아이폰 앱 개발] CATransition showing a single frame from the end of the transition before the animation starts

      CATransition showing a single frame from the end of the transition before the animation starts
     

    I am using some code which was originally taken from the Apple sample ViewTransitions to swap two views with each other.

    CATransition *animation = [CATransition animation];
    [animation setDelegate:self];
    [animation setType:kCATransitionFade];
    [animation setDuration:0.3f];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    [[container layer] addAnimation:animation forKey:@"swap"];

    When my transition executes on the devlice, I sometimes get a single frame flash of the final frame of the transition animation and then the animation plays smoothly. This gives a very jarring effect of the 2nd view which flickers in and then out again before the smooth animation executes.

    The main difference between my example and the Apple example is that my views are not full screen, I have a container UIView which contains both sub-views and I am applying my animation to the container layer instead the root view layer. I can not see that this should make much difference though.

    This issue does not happen at all in the simulator and is intermittent (about 60-70% of the time) on the device. Is anyone else seeing this behaviour and if so, how did you work around it?

    Updated with more information: The code was originally part of a multi part animation but I moved it to be triggered by a button to isolate the problem. The issue occurs in both situations.

    The animation delegates were implemented but have been removed to try and isolate the problem.

    The views are not changing during the animation and in fact [container setUserInteractionEnabled:NO] is being called (but the problem also happens without user interaction being disabled).

    I have tried starting the animation from the middle of the transition and ending before the end usingsetStartProgress and setEndProgress, again the problem persists.

    I have tried slowing the animation duration right down as well with no effect.

        262508        Dave Verwer        iphone  cocoa-touch  core-animation  objective-c  


     

    I can't post comment, but the same as teabot : I did what you said and it doesn't do the trick... Do you have more explanations on the subject ?

        1410428        Unfalkster        iphone  cocoa-touch  core-animation  objective-c  


     

    Solved, I had missed a key piece of this that I thought was irrelevant ;) After setting up the animation in the code sample above, I was swapping the views out in the same method.

    Moving it to the animationDidStart delegate fixed the issue.

        268456        Dave Verwer        iphone  cocoa-touch  core-animation  objective-c  


      Can you give some example code of this in action please? I have implemented what I understand by your description but my 'glitch frame' persists. #1226703    teabot


     

    To begin to answer your question more information is needed - for instance, how are you calling that code (e.g. is it bound to a button as an action or is it triggered automatically somehow), have you implemented the delegate methods to start and stop the animation (and what is contained within them), and are your views changing at some point during the animation? Timing between the simulator and device will be off - you should not rely on the simulator to test animation as everything will happen quicker.

    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 22. 17:23
    [아이폰 앱 개발] Converting plist to binary plist- 서버측에서 objective -c로 변환후 아이폰으로 보낼때 서버측

      Converting plist to binary plist
     

    Apple strongly recommends using the binary plist format when reading large XML-based data sets into iPhone apps. Among their reasoning is the fact that XML parsing is very taxing on the iPhone. However, this requires that files residing on the remote web server be converted first.

    For frequently-changing content, it is not acceptable to do this manually. If at all possible, I'd like to avoid having a web based app call the command line to perform the conversion (i.e., plutil).

    Are there publicly available algorithms to perform this conversion?

        264440        Brian Cline        objective-c  cocoa  cocoa-touch  iphone  core-foundation  


     

    Yes. All the plist code is part of CoreFoundation, which is opensource. CoreFoundation can be directly built and run on Linux and Windows, so you can write a CF tool using the normal APIs you would use on Mac OS X, but build and run it on other platforms.

    The particular API you want to be looking at is CFPropertyListWriteToStream(). The code for CoreFoundation is available from Apple (tarball), among other places.

    Finally depending on how often you update the file, how much processor you have to spare on the server, and how much repetition there is your data there may be one significant enhancement left that you can do. By default certain elements in binary plists are uniqued (such as strings). Other elements are not (such as arrays and dictionarts). The binary plist format allows them to be uniqued, the issue is that it is expensive to actually walk through and unique arrays and dictionaries. If you have a lot of identical arrays or dicts in your content you may see a significant size reduction by uniquing them. You can enable that by hacking up _flattenPlist() inCFBinaryPlist.c.

    If you do that make sure to test it very thoroughly, and do not do on any files you cannot update over the network, just in case a future release makes any optimizations that break that. Also, make sure you are ready to turn it off at a moments notice.

        264489        Louis Gerbarg        objective-c  cocoa  cocoa-touch  iphone  core-foundation  


      Thanks, this helps a lot. I'll probably be building this and wrapping some of these functions into a PHP module. #121576    Brian Cline


     

    It's not clear if you want to do the conversion on the iPhone or on the server. If it's on the server and you can use the Cocoa frameworks, the NSPropertyListSerialization provides services to convert between the supported plist types (string, XML, and binary) on OS X (since 10.2). There are also analogous methods in the Core Foundation library if you'd prefer to use that instead.

    To convert an XML plist to a binary one:

    NSString *xmlPlistPath; // already set
    NSString *outPath; // already set


    NSData *plistData;
    NSString *error;
    NSPropertyListFormat format;
    id plist
    ;
    plistData
    = [NSData dataWithContentsOfFile:xmlPlistPath];

    plist
    = [NSPropertyListSerialization propertyListFromData:plistData
    mutabilityOption
    :NSPropertyListImmutable
    format
    :&format
    errorDescription
    :&error];

    if(plist == nil) { // unable to parse plist
    //deal with failure -- error gives description of the error
    } else {
    binaryPlistData
    = [NSPropertyListSerialization dataFromPropertyList:plist
    format
    :NSPropertyListBinaryFormat_v1_0
    errorDescription
    :&error];
    if(binaryPlistData == nil) {//unable to create serialized plist
    // deal with failure -- error gives description of the error
    }

    if(![binaryPlistData writeToFile:outPath atomically:YES]) {
    // unable to write file
    }
    }

    See Property List Pramming Guide page on developer.apple.com for more information.

    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 22. 12:43
    [아이폰 앱 개발] [key]성능좋은 game loop만들기

    The Game Loop




    The latest version of my game loop article can now be found on my Koonsolo Game Development Blog. Click on the following link to read it: deWiTTERS Game Loop Article.

    Just for reference, here is the old one:




    Introduction

    The game loop is the heartbeat of every game, no game can run without it. But unfortunately for every new game programmer, there aren't any good articles on the internet who provide the proper information on this topic. But fear not, because you have just stumbled upon the one and only article that gives the game loop the attention it deserves.

    Thanks to my job as a game programmer, I come into contact with a lot of code for small mobile games. And it always amazes me how many game loop implementations are out there. You might wonder yourself how a simple thing like that can be written in different ways. Well, it can, and I will discuss the pros and cons of the most popular implementations, and give you the (in my opinion) best solution of implementing a game loop.

    The Game Loop

    Every game consists of a sequence of getting user input, updating the game state, handling AI, playing music and sound effects, and displaying the game. This sequence is handled through the game loop. Just like I said in the introduction, the game loop is the heartbeat of every game. In this article I will not go into details on any of the above mentioned tasks, but will concentrate on the game loop alone. That's also why I simplified the tasks to only 2 functions: updating the game and displaying it.

    Here is some example code of the game loop in it's most simplest form:

        bool game_is_running = true;
    
        while( game_is_running ) {
            update_game();
            display_game();
        }
    
    
    

    The problem with this simple loop is that it doesn't handle time, the game just runs. On slower hardware the game runs slower, and on faster hardware faster. Back in the old days when the speed of the hardware was known, this wasn't a problem, but nowadays there are so many hardware platforms out there, that we have to implement some sort of time handling. There are many ways to do this, and I'll discuss them in the following sections.

    First, let me explain 2 terms that are used throughout this article:

    FPS
    FPS is an abbreviation for Frames Per Second. In the context of the above implementation, it is the number of times display_game() is called per second.
    Game Speed
    Game Speed is the number of times the game state gets updated per second, or in other words, the number of times update_game() is called per second.

    FPS dependent on Constant Game Speed

    Implementation

    An easy solution to the timing issue is to just let the game run on a steady 25 frames per second. The code then looks like this:

        const int FRAMES_PER_SECOND = 25;
        const int SKIP_TICKS = 1000 / FRAMES_PER_SECOND;
    
        DWORD next_game_tick = GetTickCount(); 
        // GetTickCount() returns the current number of milliseconds
        // that have elapsed since the system was started
    
        int sleep_time = 0;
    
        bool game_is_running = true;
    
        while( game_is_running ) {
            update_game();
            display_game();
    
            next_game_tick += SKIP_TICKS;
            sleep_time = next_game_tick - GetTickCount();
            if( sleep_time >= 0 ) {
                Sleep( sleep_time );
            }
            else {
                // Shit, we are running behind!
            }
        }
    
    
    This is a solution with one huge benefit: it's simple! Since you know that update_game() gets called 25 times per second, writing your game code is quite straight forward. For example, implementing a replay function in this kind of game loop is easy. If no random values are used in the game, you can just log the input changes of the user and replay them later.

    On your testing hardware you can adapt the FRAMES_PER_SECOND to an ideal value, but what will happen on faster or slower hardware? Well, let's find out.

    Slow hardware

    If the hardware can handle the defined FPS, no problem. But the problems will start when the hardware can't handle it. The game will run slower. In the worst case the game has some heavy chunks where the game will run really slow, and some chunks where it runs normal. The timing becomes variable which can make your game unplayable.

    Fast hardware

    The game will have no problems on fast hardware, but you are wasting so many precious clock cycles. Running a game on 25 or 30 FPS when it could easily do 300 FPS... shame on you! You will lose a lot of visual appeal with this, especially with fast moving objects.

    On the other hand, with mobile devices, this can be seen as a benefit. Not letting the game constantly run at it's edge could save some battery time.

    Conclusion

    Making the FPS dependent on a constant game speed is a solution that is quickly implemented and keeps the game code simple. But there are some problems: Defining a high FPS will pose problems on slower hardware, and defining a low FPS will waste visual appeal on fast hardware.

    Game Speed dependent on Variable FPS

    Implementation

    Another implementation of a game loop is to let it run as fast as possible, and let the FPS dictate the game speed. The game is updated with the time difference of the previous frame.

        DWORD prev_frame_tick;
        DWORD curr_frame_tick = GetTickCount();
    
        bool game_is_running = true;
        while( game_is_running ) {
            prev_frame_tick = curr_frame_tick;
            curr_frame_tick = GetTickCount();
    
            update_game( curr_frame_tick - prev_frame_tick );
            display_game();
        }
    
    
    The game code becomes a bit more complicated because we now have to consider the time difference in the update_game() function. But still, it's not that hard.

    At first sight this looks like the ideal solution to our problem. I have seen many smart programmers implement this kind of game loop. Some of them probably wished they would have read this article before they implemented their loop. I will show you in a minute that this loop can have serious problems on both slow and fast (yes, FAST!) hardware.

    Slow Hardware

    Slow hardware can sometimes cause certain delays at some points, where the game gets "heavy". This can definitely occur with a 3D game, where at a certain time too many polygons get shown. This drop in frame rate will affect the input response time, and therefore also the player's reaction time. The updating of the game will also feel the delay and the game state will be updated in big time-chunks. As a result the reaction time of the player, and also that of the AI, will slow down and can make a simple maneuver fail, or even impossible. For example, an obstacle that could be avoided with a normal FPS, can become impossible to avoid with a slow FPS. A more serious problem with slow hardware is that when using physics, your simulation can evenexplode!

    Fast Hardware

    You are probably wondering how the above game loop can go wrong on fast hardware. Unfortunately, it can, and to show you, let me first explain something about math on a computer.

    The memory space of a float or double value is limited, so some values cannot be represented. For example, 0.1 cannot be represented binary, and therefore is rounded when stored in a double. Let me show you using python:

    >>> 0.1
    0.10000000000000001
    
    
    This itself is not dramatic, but the consequences are. Let's say you have a race-car that has a speed of 0.001 units per millisecond. After 10 seconds your race-car will have traveled a distance of 10.0. If you split this calculation up like a game would do, you have the following function using frames per second as input:
    >>> def get_distance( fps ):
    ...     skip_ticks = 1000 / fps
    ...     total_ticks = 0
    ...     distance = 0.0
    ...     speed_per_tick = 0.001
    ...     while total_ticks < 10000:
    ...             distance += speed_per_tick * skip_ticks
    ...             total_ticks += skip_ticks
    ...     return distance
    
    
    Now we can calculate the distance at 40 frames per second:
    >>> get_distance( 40 )
    10.000000000000075
    
    
    Wait a minute... this is not 10.0??? What happened? Well, because we split up the calculation in 400 additions, a rounding error got big. I wonder what will happen at 100 frames per second...
    >>> get_distance( 100 )
    9.9999999999998312
    
    
    What??? The error is even bigger!! Well, because we have more additions at 100 fps, the rounding error has more chance to get big. So the game will differ when running at 40 or 100 frames per second:
    >>> get_distance( 40 ) - get_distance( 100 )
    2.4336088699783431e-13
    
    
    You might think that this difference is too small to be seen in the game itself. But the real problem will start when you use this incorrect value to do some more calculations. This way a small error can become big, and fuck up your game at high frame rates. Chances of that happening? Big enough to consider it! I have seen a game that used this kind of game loop, and which indeed gave trouble at high frame rates. After the programmer found out that the problem was hiding in the core of the game, only a lot of code rewriting could fix it.

    Conclusion

    This kind of game loop may seem very good at first sight, but don't be fooled. Both slow and fast hardware can cause serious problems for your game. And besides, the implementation of the game update function is harder than when you use a fixed frame rate, so why use it?

    Constant Game Speed with Maximum FPS

    Implementation

    Our first solution, FPS dependent on Constant Game Speed, has a problem when running on slow hardware. Both the game speed and the framerate will drop in that case. A possible solution for this could be to keep updating the game at that rate, but reduce the rendering framerate. This can be done using following game loop:

        
        const int TICKS_PER_SECOND = 50;
        const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
        const int MAX_FRAMESKIP = 10;
            
        DWORD next_game_tick = GetTickCount();
        int loops;
        
        bool game_is_running = true;
        while( game_is_running ) {
    
            loops = 0;
            while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
                update_game();
                
                next_game_tick += SKIP_TICKS;
                loops++;
            }
            
            display_game();
        }
    
    

    The game will be updated at a steady 50 times per second, and rendering is done as fast as possible. Remark that when rendering is done more than 50 times per second, some subsequent frames will be the same, so actual visual frames will be dispayed at a maximum of 50 frames per second. When running on slow hardware, the framerate can drop until the game update loop will reach MAX_FRAMESKIP. In practice this means that when our render FPS drops below 5 (= FRAMES_PER_SECOND / MAX_FRAMESKIP), the actual game will slow down.

    Slow hardware

    On slow hardware the frames per second will drop, but the game itself will hopefully run at the normal speed. If the hardware still can't handle this, the game itself will run slower and the framerate will not be smooth at all.

    Fast hardware

    The game will have no problems on fast hardware, but like the first solution, you are wasting so many precious clock cycles that can be used for a higher framerate. Finding the balance between a fast update rate and being able to run on slow hardware is crucial.

    Conclusion

    Using a constant game speed with a maximum FPS is a solution that is easy to implement and keeps the game code simple. But there are still some problems: Defining a high FPS can still pose problems on slow hardware (but not as severe as the first solution), and defining a low FPS will waste visual appeal on fast hardware.

    Constant Game Speed independent of Variable FPS

    Implementation

    Would it be possible to improve the above solution even further to run faster on slow hardware, and be visually more atractive on faster hardware? Well, lucky for us, this is possible. The game state itself doesn't need to be updated 60 times per second. Player input, AI and the updating of the game state have enough with 25 frames per second. So let's try to call the update_game() 25 times per second, no more, no less. The rendering, on the other hand, needs to be as fast as the hardware can handle. But a slow frame rate shouldn't interfere with the updating of the game. The way to achieve this is by using the following game loop:

        const int TICKS_PER_SECOND = 25;
        const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
        const int MAX_FRAMESKIP = 5;
    
        DWORD next_game_tick = GetTickCount();
        int loops;
        float interpolation;
    
        bool game_is_running = true;
        while( game_is_running ) {
    
            loops = 0;
            while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
                update_game();
    
                next_game_tick += SKIP_TICKS;
                loops++;
            }
    
            interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
                            / float( SKIP_TICKS );
            display_game( interpolation );
        }
    
    
    
    With this kind of game loop, the implementation of update_game() will stay easy. But unfortunately, the display_game() function gets more complex. You will have to implement a prediction function that takes the interpolation as argument. But don't worry, this isn't hard, it just takes a bit more work. I'll explain below how this interpolation and prediction works, but first let me show you why it is needed.

    The Need for Interpolation

    The gamestate gets updated 25 times per second, so if you don't use interpolation in your rendering, frames will also be displayed at this speed. Remark that 25 fps isn't as slow as some people think, movies for example run at 24 frames per second. So 25 fps should be enough for a visually pleasing experience, but for fast moving objects, we can still see a improvement when doing more FPS. So what we can do is make fast movements more smooth in between the frames. And this is where interpolation and a prediction function can provide a solution.

    Interpolation and Prediction

    Like I said the game code runs on it's own frames per second, so when you draw/render your frames, it is possible that it's in between 2 gameticks. Let's say you have just updated your gamestate for the 10Th time, and now you are going to render the scene. This render will be in between the 10Th and 11Th game update. So it is possible that the render is at about 10.3. The 'interpolation' value then holds 0.3. Take this example: I have a car that moves every game tick like this:

        position = position + speed;
    
    

    If in the 10Th gametick the position is 500, and the speed is 100, then in the 11Th gametick the position will be 600. So where will you place your car when you render it? You could just take the position of the last gametick (in this case 500). But a better way is to predict where the car would be at exact 10.3, and this happens like this:

        view_position = position + (speed * interpolation)
    
    

    The car will then be rendered at position 530.

    So basically the interpolation variable contains the value that is in between the previous gametick and the next one (previous = 0.0, next = 1.0). What you have to do then is make a "prediction" function where the car/camera/... would be placed at the render time. You can base this prediction function on the speed of the object, steering or rotation speed. It doesn't need to be complicated because we only use it to smooth things out in between the frames. It is indeed possible that an object gets rendered into another object right before a collision gets detected. But like we have seen before, the game is updated 25 frames per second, and so when this happens, the error is only shown for a fraction of a second, hardly noticeable to the human eye.

    Slow Hardware

    In most cases, update_game() will take far less time than display_game(). In fact, we can assume that even on slow hardware the update_game() function can run 25 times per second. So our game will handle player input and update the game state without much trouble, even if the game will only display 15 frames per second.

    Fast Hardware

    On fast hardware, the game will still run at a constant pace of 25 times per second, but the updating of the screen will be way faster than this. The interpolation/prediction method will create the visual appeal that the game is actually running at a high frame rate. The good thing is that you kind of cheat with your FPS. Because you don't update your game state every frame, only the visualization, your game will have a higher FPS than with the second method I described.

    Conclusion

    Making the game state independent of the FPS seems to be the best implementation for a game loop. However, you will have to implement a prediction function in display_game(), but this isn't that hard to achieve.

    Overall Conclusion

    A game loop has more to it than you think. We've reviewed 4 possible implementations, and it seems that there is one of them which you should definitely avoid, and that's the one where a variable FPS dictates the game speed.

    A constant frame rate can be a good and simple solution for mobile devices, but when you want to get everything the hardware has got, best use a game loop where the FPS is completely independent of the game speed, using a prediction function for high framerates.

    If you don't want to bother with a prediction function, you can work with a maximum frame rate, but finding the right game update rate for both slow and fast hardware can be tricky.

    Now go and start coding that fantastic game you are thinking of!

    Posted by 오늘마감

    댓글을 달아 주세요

    아이폰어플개발정보2010. 10. 22. 09:08
    [아이폰 앱 개발] [iphone 개발자 인증] 인증서 인증과정

    이제 내 맥과 아이폰 개발자 홈페이지 간에 인증 과정을 거쳐야 합니다.

    이 과정을 제대로 해야 기기 연결을 제대로 할 수 있습니다.

    1. "Program Portal"에 들어 갑니다. 

    "애플 아이폰 개발자 홈페이지"에서 상단 오른쪽에 있는 아래 링크를 이용하시면 됩니다.

     

    아래와 같은 화면이 뜰겁니다. 여기서 왼쪽에 있는 메뉴를 주로 이용합니다.

     

    2. 왼쪽의 "Certificates"에 들어가서 "Development"를 클릭해 보시면, 아직 인증서가 등록되지 않은 것을 볼 수 있습니다.

    이제 인증서를 생성하도록 하겠습니다. (반드시 "Development"에서 진행하시기 바랍니다.)

     

    3. 맥의 Finder로 가셔서 "이동 > 응용프로그램 > 유틸리티 "에 가셔서 "키체인 접근"을 실행합니다.

    4. "키체인 접근"에서 "환경설정"으로 들어갑니다.


    5. "검사/복구"탭에서 4개 항목 모두 체크되어 있는지 확인합니다. 안되어 있다면 체크합니다.

    6. "인증서"탭에서 "끔, 끔, OCSP"으로 세팅되어 있는지 확인합니다. 안되어 있다면 세팅합니다.

    7. "키체인 접근"에서 "인증 지원 > 인증 기관에서 인증서 요청..."으로 들어갑니다.

    8. "애플 아이폰 개발자 홈페이지"에 등록한 "이메일 주소"와 "이름"을 적습니다. 
    이름은 홈페이지에 나와있는 Welcome 다음에 나온 대로 적으면 됩니다. 아마 "이름 성" 형태로 나올 겁니다. 나온 대로 적으면 됩니다.

    또, "요청"에서 "디스크에 저장됨"을 체크하시고, "자신이 키페어 정보 지정"도 체크하셔야 합니다.

    9. 저장여부를 묻습니다. 데스크탑에 그냥 저장 하십시요.

    10. 다음 아래와 같은 창이 뜰겁니다. "2048비트"와 "RSA"가 선택되었는지를 확인하고 "계속"을 누릅니다.

    11. 바탕화면에 "Certificate..."하는 파일이 생성되었을 겁니다. "완료"를 누르세요.

    12. 다시 "애플 아이폰 개발자 홈페이지"로 돌아와서 "Program Portal"로 들어갑니다. 좌측 메뉴에서 "Certificates"를 선택하면 다음과 같은 화면이 나올겁니다.

    여기에서 "Request Certificae"버튼을 클릭합니다.

    13. "파일 선택" 버튼을 클릭하여, 방금 전 키체인에서 생성한 파일을 선택하고, "Submit" 버튼을 클릭합니다.

    14. 다시 "Certificate" 화면으로 돌아 오는데, 새로 고침을 하다 보면 Action에 "Approve" 버튼이 생성됩니다. "Approve"가 생기면 버튼을 클릭합니다.
    다음, "click here to download now" 를 클릭하여 파일을 다운로드 받습니다.

    15. 다운로드 받은 파일을 실행시키면 아래와 같이 묻습니다. "승인"을 누르면 됩니다.

    16. 다시 홈페이지에서 새로고침을 해보면

    이번엔 "Download" 버튼이 생겨 있습니다. 이 버튼을 클릭해서 파일을 다운로드 받습니다.

     

    17. 다운로드 받은 파일을 실행시켜 승인합니다.

    18. 다시 "키체인 접근"으로 들어가 보면 인증서가 생성된 것을 확인 하실 수 있습니다.

    Posted by 오늘마감

    댓글을 달아 주세요