如果声明hack,是否有更好的方法来写这个?

时间:2012-07-14 13:50:12

标签: java if-statement

我正在拍摄一个简单的侧卷轴游戏的实验性第一枪。如果玩家在某个方向上移动得太远,我会使用此代码重新定位屏幕。

有没有更好的方法来写它?我觉得我在滥用这种语言,但它很好用,我认为它可能没问题。

public void adjustFrameIfNecessary()
{
    int dx, dy;
    if ((dx = (GAME_WIDTH - GAME_WIDTH / 3) - player.x) < 0 || (dx = GAME_WIDTH / 3 - player.x) > 0 || (dx = 0) == 0);
    if ((dy = (GAME_HEIGHT - GAME_HEIGHT / 3) - player.y) < 0 || (dy = GAME_HEIGHT / 3 - player.y) > 0 || (dy = 0) == 0);

    if(dx != 0 || dy != 0)
    {
        for (Drawable shiftMe : drawables)
        {
            shiftMe.unconditionalShift(dx, dy);
        }
    }

}

修改

关于每个人的意见,为了使其更具可读性,我已将其更改为

public void adjustFrameIfNecessary()
{
    int dx, dy;

    assignX:
    {
        dx = (GAME_WIDTH - GAME_WIDTH / 3) - player.x;
        if(dx < 0) break assignX;
        dx = GAME_WIDTH / 3 - player.x;
        if(dx > 0) break assignX;
        dx = 0;
    }

    assignY:
    {
        dy = (GAME_HEIGHT - GAME_HEIGHT / 3) - player.y;
        if(dy < 0) break assignY;
        dy = GAME_HEIGHT / 3 - player.y;
        if(dy > 0) break assignY;
        dy = 0;
    }

    if (dx != 0 || dy != 0)
    {
        for (Drawable shiftMe : drawables)
        {
            shiftMe.unconditionalShift(dx, dy);
        }
    }

}

这样更好吗?

编辑2

public void adjustFrameIfNecessary()
{
    int dx = calculateShift(GAME_WIDTH, frameReference.x);
    int dy = calculateShift(GAME_HEIGHT, frameReference.y);

    if (dx != 0 || dy != 0)
    {
        for (Drawable shiftMe : drawables)
        {
            shiftMe.unconditionalShift(dx, dy);
        }
    }
}

我认为现在很清楚。谢谢大家。

5 个答案:

答案 0 :(得分:5)

我不确定我理解你为什么在顶部有if个陈述。您应该在初始化时简单地分配变量。

dx = (GAME_WIDTH - GAME_WIDTH / 3) - player.x)
dy = (GAME_HEIGHT - GAME_HEIGHT / 3) - player.y)

无论你的if声明如何,他们都会被分配到那里。如果它重新启动第三个条件,那么它已经 为零,因此没有理由分配它。丢弃两个if语句,而只是坚持直接变量赋值。将条件保持在for循环之上,这是您需要进行的唯一检查。

答案 1 :(得分:4)

您的if语句令人困惑。如果您(或其他任何人)需要在以后更改它,可能会非常困难并且容易出错。

制作不仅可以工作,而且可维护的代码是一个好习惯。既然你需要它,你应该让它更易于维护。

将if语句分解为有意义的变量并使用多行。你不是在为高尔夫球场代码比赛而写作?

你以后会感谢你自己。

答案 2 :(得分:1)

怎么样?

/* calculate offset to center */
dx = X_current_center - player.x;
dy = Y_current_center - player.y;

if (abs(dx) > MARGIN || abs(dy) > MARGIN)
    /* recenter */

答案 3 :(得分:1)

难以理解,但我明白你的观点。但有一件事:为什么不对x和y重复使用相同的检查?通过使用三元运算符,您可以减少一次黑客攻击。

static int toBounds(int max, int curr) {
  int ret;
  return ((ret = (max - max/3) - curr) < 0 || (ret = max/3 - curr) > 0)? ret : 0;
}

答案 4 :(得分:1)

改进此类代码的想法通常是使用数学:)

首先,抱歉这篇长篇文章。如果你亲自见过我,请不要问我这个话题,我不会再说话了。

短版

这样做:

/**
 * Computes the distance from a point x to an interval [a,b]
 */
public static int distanceToInterval( int x, int a, int b ){
   return x<a? (a-x): ( x>b? (b-x):0 ); 
   // alternative: 
   // return Math.max( a - x, 0 ) + Math.min( b - x, 0 ); 
}

// then use as 
int dx = distanceToInterval( player.x, GAME_WIDTH/3, GAME_WIDTH*2/3 ); 
int dy = distanceToInterval( player.y, GAME_HEIGHT/3, GAME_HEIGHT*2/3 ); 

长版

您的初始陈述

if ((dx = (GAME_WIDTH - GAME_WIDTH / 3) - player.x) < 0 || 
    (dx = GAME_WIDTH / 3 - player.x) > 0 || 
    (dx = 0) == 0);

这可以通过将它变成一个......来清理它。

...更长版本

dx1 = GAME_WIDTH*2/3 - player.x; 
dx2 = GAME_WIDTH*1/3 - player.x; 
dx3 = 0; 

if( dx1 < 0 ) dx = dx1; 
else if( dx2 > 0 ) dx = dx2; 
else dx = dx3; 

这是非常清楚的。我现在可以看到你正在尝试做什么并把它整理成一句话: 如果玩家不在屏幕的中间三分之一,我们想移动屏幕

让它更加清晰

if( player.x < GAME_WIDTH/3 ) dx = GAME_WIDTH/3 - player.x;  // positive num
else if( player.x > GAME_WIDTH*2/3 ) dx = GAME_WIDTH*2/3 - player.x; // negative num
else dx = 0; // no shift

你可以看到我重新排序了你的陈述,我首先检查左边界,然后检查右边界。如果你来自一个从右到左阅读的国家,你可能会发现另一个方向更直观:)

这个是我选择的解决方案。 它简短,可读,非常完美:)

然而,如果你想让它更简洁,你可以更进一步

做数学技巧

你需要明白这三种情况是完全排他性的,它们不可能同时发生。让我们回到使用更多变量:

// on the left side we shift a positive number, or not at all 
dx1 = Math.max( GAME_WIDTH/3 - player.x, 0 ); 
// on the right side we shift a negative amount, or not at all 
dx2 = Math.min( GAME_WIDTH*2/3 - player.x, 0 ); 

现在看看这个美丽:

  • 如果GAME_WIDTH/3-player.x > 0,则GAME_WIDTH*2/3 - player.x > 0 因此Math.min(...,0) = 0
  • 如果GAME_WIDTH*2/3 - player.x < 0,则GAME_WIDTH*1/3 - player.x < 0 因此Math.max(...,0) = 0

这意味着您可以简单地添加两个来计算总班次。这就是你的代码的样子:

int dx = 
     Math.max( GAME_WIDTH/3 - player.x, 0 ) + // too far to the left? 
     Math.min( GAME_WIDTH*2/3 - player.x, 0 ); // or too far to the right? 

多一点抽象

无论你选择哪种变体,现在都很容易把它放在一个方法中。 但是,让它比这个特殊情况更有意义。我会建议

/**
 * Computes the distance from a point x to an interval [a,b]
 */
public static int distanceToInterval( int x, int a, int b ){
   return 
       Math.max( a - x, 0 ) + // too far to the left? 
       Math.min( b - x, 0 ); // or too far to the right? 
}

// now use as 
int dx = distanceToInterval( player.x, GAME_WIDTH/3, GAME_WIDTH*2/3 ); 
int dy = distanceToInterval( player.y, GAME_HEIGHT/3, GAME_HEIGHT*2/3 ); 

P.S。请注意,我已在此帖中将GAME_WIDTH - GAME_WIDTH/3替换为GAME_WIDTH*2/3。这两个用整数数学给出略有不同的结果,但我更喜欢短版本,因为我发现它更直观(&#34;屏幕的三分之二&#34; vs&#34;整个屏幕然后三分之一&# 34。)

相关问题