我正在写一款Android游戏。在游戏中,不同颜色的块会掉到地上。当具有相同颜色的两个块彼此叠加时,它们将合并为一个颜色较深的块。但是,我观察到具有相同颜色的块有时不会合并。经过一些调试后,我发现它们实际上颜色略有不同:-16757700和-16757444。我使用Color.colorToHSV
和Color.HSVToColor
使颜色变深,如下面的代码所示(checkLanded
方法)。所以我认为这两种hsv方法一定有问题。这是我的代码(实际上我不认为代码有任何其他问题,你可以看一下checkLanded
方法。但是我粘贴了其他代码,因为问题可能不在我认为的地方几乎滚动到底部,你会看到checkLanded
方法):
package com.shades;
import android.graphics.Color;
import android.support.annotation.IntDef;
import com.shades.util.BlockView;
import com.shades.util.Timer;
import java.util.HashMap;
import java.util.Random;
public class Block {
private static Random r = new Random ();
private static HashMap<Integer, Float> colorValuesMap;
@IntDef ({LEFT, RIGHT})
public @interface Direction {}
public static final int LEFT = -1;
public static final int RIGHT = 1;
static {
colorValuesMap = new HashMap<> ();
colorValuesMap.put (4, 0.1F);
colorValuesMap.put (3, 0.3F);
colorValuesMap.put (2, 0.5F);
colorValuesMap.put (1, 0.7F);
colorValuesMap.put (0, 0.9F);
}
private int x;
private int y;
private int color;
protected Timer timer;
public int getX() {
return x;
}
public int getY() {
return y;
}
private void setY(int y) {
Block[][] matrix = Game.getInstance ().getBlockMatrix ();
matrix[this.x][this.y] = null;
this.y = y;
matrix[this.x][this.y] = this;
BlockView.updateViews ();
}
private void setX(int x) {
Block[][] matrix = Game.getInstance ().getBlockMatrix ();
matrix[this.x][this.y] = null;
this.x = x;
matrix[this.x][this.y] = this;
BlockView.updateViews ();
}
private void setXY (int x, int y) {
Block[][] matrix = Game.getInstance ().getBlockMatrix ();
matrix[this.x][this.y] = null;
this.y = y;
this.x = x;
matrix[x][y] = this;
BlockView.updateViews ();
}
public int getColor () {
return color;
}
public Block(int x, int y) {
setXY (x, y);
this.y = y;
float[] hsv = new float[3];
hsv[0] = Game.getInstance ().getHueNumber ();
hsv[1] = 1F;
hsv[2] = colorValuesMap.get (r.nextInt (4));
color = Color.HSVToColor (hsv);
BlockView.updateViews ();
timer = new Timer (new Runnable () {
@Override
public void run() {
moveDown ();
}
}, 1000, true);
}
private void moveDown () {
//if reached bottom
if (getY () == Game.MATRIX_HEIGHT - 1) {
timer.stopTimer ();
Game.getInstance ().nextBlock (r);
return;
}
color = Game.getInstance ().getBlockViewMatrix ()[x][y].getColor ();
Block[][] matrix = Game.getInstance ().getBlockMatrix ();
if (checkLanded (matrix[x][y + 1])) {
Game.getInstance ().nextBlock(r);
return;
}
setY (getY () + 1);
}
private boolean checkLanded(Block blockBelow) {
//if it can merge into another block
float[] currentHSV = new float[3];
Color.colorToHSV (color, currentHSV);//here is the possible inaccurate method
if (blockBelow != null &&
blockBelow.getColor () == color &&
currentHSV[2] != colorValuesMap.get (4)) {
Color.colorToHSV (blockBelow.getColor (), currentHSV);
currentHSV[2] -= 0.2F;
blockBelow.color = Color.HSVToColor (currentHSV); //here is the possible inaccurate method
selfDestroy ();
timer.stopTimer ();
//if the block below is not the block at the bottom
if (blockBelow.getY () != Game.MATRIX_HEIGHT - 1) {
blockBelow.checkLanded (Game.getInstance ().
getBlockMatrix ()[blockBelow.getX ()][blockBelow.getY () + 1]);
}
return true;
}
//if a block is touched
if (blockBelow != null &&
blockBelow.getColor () != color) {
timer.stopTimer ();
return true;
}
return false;
}
private void selfDestroy () {
Game.getInstance ().getBlockMatrix ()[x][y] = null;
BlockView.updateViews ();
}
private boolean checkPositionValid (int x, int y) {
return !(x < 0 || x >= Game.MATRIX_WIDTH ||
y < 0 || y >= Game.MATRIX_HEIGHT)
&& Game.getInstance ().getBlockMatrix ()[x][y] == null;
}
public void moveHorizontally (@Direction int direction) {
if (checkPositionValid (x + direction, y)) {
setX (x + direction);
}
}
}
有人可以告诉我Color.colorToHSV
和Color.HSVToColor
是不准确的还是我做错了什么?
只是为了通知你,如果有帮助,Game.getInstance().getHueNumber()
会返回167
答案 0 :(得分:0)
过了一段时间,我找到了解决方案。根据@Cinnam的评论,我知道HSV颜色使用float
s并且它们是不准确的。 RGB对我来说不是一个好主意,因为我不能轻易知道色调。
根据Steve McConnell的 Code Complete 2nd Edition ,第12.3节:
......一种有效的方法是确定这些值是否足够接近。通常,您编写一个equals()函数,如果值足够接近则返回true,否则返回false。
我认为两种略有不同的颜色“大致相等”所以我写了一个这样的方法:
private boolean intColorEquals(int color1, int color2) {
final int MAXIMUM_ERROR = 1000;
return Math.abs (color1 - color2) < MAXIMUM_ERROR;
}
private boolean floatEquals (float a, float b) {
final float MAXIMUM_ERROR = 0.05F;
return Math.abs (a - b) < MAXIMUM_ERROR;
}
我替换了颜色之间的所有比较和浮动之间的比较。
我真的不知道我自己的问题的答案是否应该是这样的风格。所以,如果我做错了什么,请告诉我。