我正在拍摄一个简单的侧卷轴游戏的实验性第一枪。如果玩家在某个方向上移动得太远,我会使用此代码重新定位屏幕。
有没有更好的方法来写它?我觉得我在滥用这种语言,但它很好用,我认为它可能没问题。
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);
}
}
}
我认为现在很清楚。谢谢大家。
答案 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。)