使用 CGAffineTransformMakeRotation 来回滑动触摸中的图像旋转会使 fps 下降一半

发布于 2024-11-10 10:25:45 字数 5898 浏览 0 评论 0原文

在 3D 游戏中,优化后我在 iPad2 上达到了 60fps,主运行循环位于辅助线程中, 使用界面构建器在主线程上构建UI,(这个问题是关于主线程的UI)

我有两个控制器,一个油门向上,和一个用于在使用触摸交互的UI中滚动的摇杆,你可以看到摇杆在下面这张图片中。

它有 180 度的旋转运动,正如您可以从该图像

在此处输入图像描述

如果我运行游戏,并且然后用我的拇指在这根棍子上来回擦洗,(从 0 度疯狂滚动到 -180 度) fps 下降到 33fps 而不是 60fps..

只需从下面的代码列表中注释掉下面的这一行,就可以将 fps 恢复到60fps,(我用拇指擦洗,游戏确实在滚动,但是这根棍子的图像当然不会移动),因此可以在不更新这根棍子的图像的情况下以全帧速率玩游戏,(表明它仅是这个例程吗)用这种方法更新和转换图像极大地影响了我的帧率。请参阅下面的代码,您认为有办法解决此性能问题吗? (否则我将不得不有一些通用的圆形区域,其中只有一个圆圈代表触摸区域,以给出您在某些游戏中看到的滚动概念,例如我认为的《无限之剑》..但我更愿意拥有这个交互式图像显示真正的目的。您是否看到我需要更改的内容?

  joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians

这是已设置的 viewController 的相关代码,“joypad”是您在上面看到的图像,油门是一个不同的图像,它会影响 fps,但不会影响到上面这个单一调用的程度,因为油门只是将图像移动到正确的位置,而不是使用这个 CGAffineTransformMakeRotation,但该操作确实使 fps 下降了大约 8fps。

@interface stickController : UIViewController
{
    IBOutlet UIImageView *throttleStickCap;
    IBOutlet UIImageView *joypadCap;
etc......

@implementation stickController

@synthesize frontViewButton, backViewButton, leftViewButton, rightViewButton, upViewButton, gunSight;

//------------------------------------------------------------------------------------
- (void)viewDidLoad
{
NSLog(@"viewDidLoad");
    [super viewDidLoad];
    throttleStick = throttleStickCap.frame;
    throttleStickCenterx = throttleStickCap.center.x;
    throttleStickCentery = throttleStickCap.center.y;
    throttleStickMax = 72.0f;
    throttleStickMin = -7.0f;

    joypad = joypadCap.frame;
    joypadCenterx = joypadCap.center.x;
    joypadCentery = joypadCap.center.y;
    joypadMax = 50.0f;
    joypadMin = -50.0f;

    theStickController = self;
}

//------------------------------------------------------------------------------------
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSSet *allTouches = [event allTouches];
    for (UITouch *touch in allTouches)
    {
        CGPoint touchLocation = [touch locationInView:self.view];

        if (CGRectContainsPoint(throttleStick, touchLocation))
        {
            throttleStickTouchHash = [touch hash];
        }

        if (CGRectContainsPoint(joypad, touchLocation))
        {
            joypadTouchHash = [touch hash];

            CGPoint touchLocation = [touch locationInView:self.view];
            float dx = touchLocation.x - (float)joypadCenterx;
            float dy = touchLocation.y - (float)joypadCentery;

            distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));

            if (distance > joypadMax)
            {
                enoughDistance = shootDistance;
                createBulletSet();
            }
        }
    }
}

//------------------------------------------------------------------------------------
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSSet *allTouches = [event allTouches];

    for (UITouch *touch in allTouches)
    {
        if ([touch hash] == throttleStickTouchHash)
        {
            CGPoint touchLocation = [touch locationInView:self.view];

            distance = throttleStickCentery - touchLocation.y;

            if (distance > throttleStickMax)
            {
                throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMax);
                throttle = throttleStickMax;
            }
            else if (distance < throttleStickMin)
            {
                throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMin);
                throttle = throttleStickMin;
            }
            else
            {
                throttleStickCap.center = CGPointMake(throttleStickCap.center.x, touchLocation.y);
                throttle = distance;
            }
            throttle *= .10;
            throttleStick = throttleStickCap.frame;
        }

        if ([touch hash] == joypadTouchHash)
        {
            CGPoint touchLocation = [touch locationInView:self.view];
            float dx = touchLocation.x - (float)joypadCenterx;
            float dy = touchLocation.y - (float)joypadCentery;

            distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));

            if (distance > joypadMax) createBulletSet();
                else enoughDistance = shootDistance;

            if (dx > joypadMax) roll = joypadMax;
                else if (dx < joypadMin) roll = joypadMin;
                else roll = dx;

            joypad = joypadCap.frame;

            touchAngle = atan2(dy, dx) + 1.570796;

            if ((dx < 0.0f) && (dy > 0.0f)) touchAngle = -1.570796;
            else if ((dx > 0.0f) && (dy > 0.0f)) touchAngle = 1.570796;

    //      joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians
        }
    }
}

//------------------------------------------------------------------------------------
- (void)forceTouchesEnd
{
    throttleStickMoving = NO;
    throttleStickTouchHash = 0;
    throttle = 0.0f;
    throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery);
    throttleStick = throttleStickCap.frame;

    joypadMoving = NO;
    joypadTouchHash = 0;
    roll = 0.0f;
    joypadCap.transform = CGAffineTransformMakeRotation(0.0f); //rotation in radians
    joypad = joypadCap.frame;
}

//------------------------------------------------------------------------------------
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    for (UITouch *touch in touches)
    {
        if ([touch hash] == throttleStickTouchHash)
        {
            throttleStickTouchHash = 0;
        }

        if ([touch hash] == joypadTouchHash)
        {
            joypadTouchHash = 0;
            roll = 0.0f;

            joypad = joypadCap.frame;

            return;
        }
    }
}

in a 3D game, after optimization i have hit 60fps on an iPad2, the main runloop is in a secondary thread,
with the interface builder built UI on the main thread, (this question is about the UI of the main thread)

i have two controllers, a throttle up, and a stick for roll in the UI that uses touch interaction, you can see the stick in this image below.

it has a rotation movement of 180 degrees as you can imagine from this image

enter image description here

if i run the game, and then scrub back and forth with my thumb on this stick, (rolling wildly from 0 degrees to -180 degrees) the fps drops to 33fps instead of 60fps..

simply commenting out this line below from the code listing below, brings the fps back to 60fps, (i scrub with my thumb and the game does it's rolling, but the image of this stick of course does not move) so it is possible to play the game at full fps without updating the image of this stick, (showing that it is this routine alone) this updating and transforming of the image with this method is greatly effecting my fps. see this code below, do you think there is a way around this performance hit? (otherwise i'm going to have to have some generic round area with just a circle representing the touch area to give an idea of roll that you see in some games like i think infinity blade.. but i would much rather have this interactive image showing the true purpose. do you see anything that i am missing? need to change? would be better?

  joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians

here is the relevant code from the viewController that is set up, the "joypad" is the image you see above, the throttle is a different image and it is effecting the fps but not to the extent of this single call above because the throttle is just moving the image to the correct place, and not using this CGAffineTransformMakeRotation. but that operation does drop the fps by about 8fps.

@interface stickController : UIViewController
{
    IBOutlet UIImageView *throttleStickCap;
    IBOutlet UIImageView *joypadCap;
etc......

@implementation stickController

@synthesize frontViewButton, backViewButton, leftViewButton, rightViewButton, upViewButton, gunSight;

//------------------------------------------------------------------------------------
- (void)viewDidLoad
{
NSLog(@"viewDidLoad");
    [super viewDidLoad];
    throttleStick = throttleStickCap.frame;
    throttleStickCenterx = throttleStickCap.center.x;
    throttleStickCentery = throttleStickCap.center.y;
    throttleStickMax = 72.0f;
    throttleStickMin = -7.0f;

    joypad = joypadCap.frame;
    joypadCenterx = joypadCap.center.x;
    joypadCentery = joypadCap.center.y;
    joypadMax = 50.0f;
    joypadMin = -50.0f;

    theStickController = self;
}

//------------------------------------------------------------------------------------
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSSet *allTouches = [event allTouches];
    for (UITouch *touch in allTouches)
    {
        CGPoint touchLocation = [touch locationInView:self.view];

        if (CGRectContainsPoint(throttleStick, touchLocation))
        {
            throttleStickTouchHash = [touch hash];
        }

        if (CGRectContainsPoint(joypad, touchLocation))
        {
            joypadTouchHash = [touch hash];

            CGPoint touchLocation = [touch locationInView:self.view];
            float dx = touchLocation.x - (float)joypadCenterx;
            float dy = touchLocation.y - (float)joypadCentery;

            distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));

            if (distance > joypadMax)
            {
                enoughDistance = shootDistance;
                createBulletSet();
            }
        }
    }
}

//------------------------------------------------------------------------------------
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    NSSet *allTouches = [event allTouches];

    for (UITouch *touch in allTouches)
    {
        if ([touch hash] == throttleStickTouchHash)
        {
            CGPoint touchLocation = [touch locationInView:self.view];

            distance = throttleStickCentery - touchLocation.y;

            if (distance > throttleStickMax)
            {
                throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMax);
                throttle = throttleStickMax;
            }
            else if (distance < throttleStickMin)
            {
                throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMin);
                throttle = throttleStickMin;
            }
            else
            {
                throttleStickCap.center = CGPointMake(throttleStickCap.center.x, touchLocation.y);
                throttle = distance;
            }
            throttle *= .10;
            throttleStick = throttleStickCap.frame;
        }

        if ([touch hash] == joypadTouchHash)
        {
            CGPoint touchLocation = [touch locationInView:self.view];
            float dx = touchLocation.x - (float)joypadCenterx;
            float dy = touchLocation.y - (float)joypadCentery;

            distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));

            if (distance > joypadMax) createBulletSet();
                else enoughDistance = shootDistance;

            if (dx > joypadMax) roll = joypadMax;
                else if (dx < joypadMin) roll = joypadMin;
                else roll = dx;

            joypad = joypadCap.frame;

            touchAngle = atan2(dy, dx) + 1.570796;

            if ((dx < 0.0f) && (dy > 0.0f)) touchAngle = -1.570796;
            else if ((dx > 0.0f) && (dy > 0.0f)) touchAngle = 1.570796;

    //      joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians
        }
    }
}

//------------------------------------------------------------------------------------
- (void)forceTouchesEnd
{
    throttleStickMoving = NO;
    throttleStickTouchHash = 0;
    throttle = 0.0f;
    throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery);
    throttleStick = throttleStickCap.frame;

    joypadMoving = NO;
    joypadTouchHash = 0;
    roll = 0.0f;
    joypadCap.transform = CGAffineTransformMakeRotation(0.0f); //rotation in radians
    joypad = joypadCap.frame;
}

//------------------------------------------------------------------------------------
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    for (UITouch *touch in touches)
    {
        if ([touch hash] == throttleStickTouchHash)
        {
            throttleStickTouchHash = 0;
        }

        if ([touch hash] == joypadTouchHash)
        {
            joypadTouchHash = 0;
            roll = 0.0f;

            joypad = joypadCap.frame;

            return;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文