I'm having a minor issue with the borders of my grid pane. The grid pane is 10x10 and contains rectangles.
The rectangles in the grid have 3 states: inactive (white), active (gray) and enabled (random color).
The grid pane has setGridLinesVisible set to false and the rectangles have white borders as to make it seem like only the active and enabled rectangles are inside the grid.
This works perfectly but I'm getting some weird effect where the borders extend to the end of the grid pane as seen in the following screenshot:
Is there a way to remove these grey lines?
Thanks!
EDIT: this his how the rectangles are added to the grid pane:
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 10; j++) {
StackPane guidePane = new StackPane();
Label l = new Label();
l.setTextFill(Color.WHITE);
Rectangle b = new Rectangle();
guidePane.getChildren().add(b);
guidePane.getChildren().add(l);
ourGrid.add(guidePane, i, j); << this is the GridPane
blockArray[i][j] = guidePane;
}
}
Solution removed from question body:
You have to set the stroke color for the rectangles with b.setStroke(Color.WHITE); to get rid of the grey lines.
Related
For example, I have a png file and I want to turn all pixels in a png file that has the same RGB value into another color. I am working on an interactive map with provinces and I want to have a file where all provinces have different RGB values and use province colors as an id system. Problem is that I don't know how to change RGB value to another
If its a Texture2D, you can change the pixels as follow:
Texture2D texture = new Texture2D(128, 128); // load your texture here
Color colortrigger = Color.Blue; // color triggers to change
for (int y = 0; y < texture.height; y++)
{
for (int x = 0; x < texture.width; x++)
{
if(texture.GetPixel(x,y) == colortrigger)
{
// Change the pixel to another color
texture.SetPixel(x, y, Color.Yellow);
}
}
}
texture.Apply();
I am trying to create a basic tower defense game where I have set up my cell size to be 0.5 X and 0.5 Y (so that the player can place their towers more freely, think WC3).
This causes problems when I later in the game wants to check if a grid cell is occupied, because some cells will seem to be taken, but actually are not.
Here's an image to illustrate my problem:
The black square is rendered over 4 cells, but only 1 of the cells are occupied (the white square in the lower left corner of the black square).
Have anyone else faced this particular problem and knows how to solve this or are there any other solutions that you would like to recommend? :)
Thanks in advance!
Though I'm unsure how the unity Grid component works I have used the following approach in one of my grid based games. Note however that I implemented my own grid for this, which contain custom grid tiles. But maybe the same logic can be applied to the unity grid
This grid was just a simple grid made like this
for (int i = 0; i < terrainLength; i++)
{
for (int j = 0; j < terrainWidth; j++)
{
GameObject tile = Instantiate(gridTilePrefab, new Vector3(posX + i * gridCube.transform.localScale.x, posY + terrainHeight, posZ + j * gridCube.transform.localScale.z), Quaternion.identity);
tile.name = "grid[" + i + "," + j + "]";
tile.transform.parent = gridParent.transform;
}
}
These grid tiles would have a boolean isOccupied. That would be set to true if an object is placed on it, and false if not.
To check wether or not it was occupied I would simply cast a raycast up from the center of the tile and check for any collision while in the builder phase (No need to do these checks during play!) the implemented was a simple as this:
Class GridTile
{
public bool isOccupied {get; private set;}
public void BuildStageLoop()//this loops like an update while we're in building stage
{
if (Physics.Raycast(transform.position, Vector3.up * 2, out hit))
{
tileOccupied = true;
}
else
{
tileOccupied = false;
}
}
}
And on the placing object I would just check if every tile underneath it had isOccupied set to false. To check for the tiles underneath it I would do a boxRayCast downwards with the width and length of the object you're trying to place, and extending a bit underneath the object so it can collide with the grid tiles.
I'm working on a simple board game implementation in JavaFX8.
For the game board, my decision was to use a 10x10 GridPane and fill it's cells with Rectangles in form's initialize method.
private void drawBoard() {
gridpaneBoard.getChildren().clear();
for (int y = 0; y < gridpaneBoard.getRowConstraints().size(); y++)
for (int x = 0; x < gridpaneBoard.getColumnConstraints().size(); x++) {
Rectangle rect = new Rectangle(55,55);
rect.setStroke(Color.BLACK);
Tile tile = GameController.getInstance().getBoard().getTile(x, y);
if (tile.hasBranch())
rect.setFill(QuestionDifficulty.values()[tile.getBranch()
.getQuestion().getQuestion()
.getLevel()].getColor());
else
rect.setFill(Color.WHITE);
gridpaneBoard.add(rect, x, y);
gridpaneBoard.add(new Label(String.valueOf(tile.getNumber())), x, y);
}
}
In order to animate player token movement after dice rolls, I figured I need to know the center x & center y of each tile (to create a path transition from source tile to destination tile).
I've tried all sorts of answers given to other people's questions, but everything returned 0,0 for me.
This is the container hierarchy in this scene:
This is how the output looks at the moment:
If GridPane is fine for what I'm trying to achieve, how can I get a child's (in this case a rectangle's) screen / scene center x,y?
If GridPane is not fine, can you point me to alternatives and how I can achieve what I want then..
Thank you!
You can simply call getBoundsInParent to get the dimensions of the Node in it's parent.
The following example is a bit simplified, but it should demonstrate the approach nonetheless:
#Override
public void start(Stage primaryStage) {
GridPane gridpaneBoard = new GridPane();
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
Rectangle rect = new Rectangle(55, 55);
rect.setStroke(Color.BLACK);
rect.setFill((x + y) % 2 == 0 ? Color.WHITE : Color.DARKGRAY);
gridpaneBoard.add(rect, x, y);
}
}
gridpaneBoard.setOnMouseClicked(evt -> {
Node target = evt.getPickResult().getIntersectedNode();
if (target != gridpaneBoard) {
// in your case you'd need to make sure this is not the Label
Bounds bounds = target.getBoundsInParent();
System.out.println("bounds = " +bounds);
System.out.println("centerX = " +(bounds.getMinX() + bounds.getWidth()/2));
System.out.println("centerY = " +(bounds.getMinY() + bounds.getHeight()/2));
}
});
Scene scene = new Scene(gridpaneBoard);
primaryStage.setScene(scene);
primaryStage.show();
}
If coordinates different to the GridPane coordinates are required, you could use getBoundsInLocal in combination with localTo... instead:
Bounds bounds = target.localToScene(target.getBoundsInLocal());
for scene bounds or
Bounds bounds = target.localToScreen(target.getBoundsInLocal());
for screen bounds.
Note: This works independent from any properties modifying how GridPane layouts it's children.
You can use :
-GridPane.getColumnIndex(Node) to get the column index.
-GridPane.getRowIndex(Node) to get the row index.
-Since you know the Width and the Height (55,55) of your child (Rectangle) you can just calculate its centerX, centerY which is relative to its position in the container, but since you use a GridPane I don't think it is possible since this one has Constraints. You can fix it by changing the container of your object or completely redraw it inside another raw/column, here is an example Replace a node at (row,col).
Using JavaFX8 and JDK 1.8.0_74 in IntelliJ, I created a basic pixel editor app. I have two windows(stages). One is a 32x128 matrix of Circle Objects placed in a Grid Pane and the other, a Tools widow; I have one Controller.java. Using the mouse, the Tools window provides tools to draw lines, rectangles, etc. and a menu for Setup, Files and Playlists. The Files menu presents the user with Open, SaveAs and Delete. To view a saved pixel art file, the user clicks Open and via the FileChooser, the selected file is opened and each Circle’s color property is displayed. The saved pixel art File can be sent via Wi-Fi to an RGB LED matrix that’s also 32x128.
To view pics and video go to: https://virtualartsite.wordpress.com/
I can scroll a displayed pixel art file left, right, up or dow using Timeline. However, I would also like to wrap the pixel image but have failed to eliminate small anomalies that appear at the beginning of the wrap while the remaining 95% of the wrap is correct?
The critical code for class WrapLeft is as follows:
public static void runAnimation() {
timeline = new Timeline(
new KeyFrame(Duration.millis(200), event -> {
wrapFileLeft(pixelArray);
}));
timeline.setCycleCount(100);
timeline.play();
}
public static void wrapFileLeft(Circle[][] pixelArray){
// save pixelArray[r][0] in pixelArrayTmp[r][0] and wrap to end, pixelArray[r][col-1]
Circle[] pixelArrayTmp = new Circle[row];
for (int r = 0; r < row; r++) {
pixelArrayTmp[r] = pixelArray[r][0];
}
// move all the pixelArray columns one column to the left
for (int c = 0; c < col-1; c++) {
for (int r = 0; r < row; r++) {
Color color = (Color) pixelArray[r][c+1].getFill();
pixelArray[r][c].setFill(color);
}
}
// move the pixelArrayTmp[r][0] column into the new, blank, end column of pixelArray[r][col-1]
for (int r = 0; r < row; r++) {
Color color = (Color) pixelArrayTmp[r].getFill();
pixelArray[r][col-1].setFill(color);
} } }
The logic is to temporarily save column 0, shift all the remaining columns to the left one position and replace column 127 with column 0. This is all done in one CycleCount(). The anomalies occur in the first four shifts left; the Circle Objects with colors other than black get changed to an adjacent color. But after four shifts, all remaining shifts appear to be correct?
My best guess is the logical order of execution gets out of order because I not using Timeline properly or trying to execute too much in a single KeyFrame? Increasing the duration doesn’t seem to affect the anomalies.
Thanks for your help.
Logically, your solution is wrong, you are storing referencing to circles in a temporary array, then changing the fill of the referenced circles, then using the updated referenced fill to set the new fill.
Instead of storing references to circles, store the fill values themselves.
public void wrapItLeft(Circle[][] pixelArray){
// save pixelArray[r][0] in pixelArrayTmp[r][0] and wrap to end, pixelArray[r][col-1]
Paint[] pixelArrayTmp = new Paint[N_ROWS];
for (int r = 0; r < N_ROWS; r++) {
pixelArrayTmp[r] = pixelArray[r][0].getFill();
}
// move all the pixelArray columns one column to the left
for (int c = 0; c < N_COLS-1; c++) {
for (int r = 0; r < N_ROWS; r++) {
Color color = (Color) pixelArray[r][c+1].getFill();
pixelArray[r][c].setFill(color);
}
}
// move the pixelArrayTmp[r][0] column into the new, blank, end column of pixelArray[r][col-1]
for (int r = 0; r < N_ROWS; r++) {
pixelArray[r][N_COLS-1].setFill(pixelArrayTmp[r]);
}
}
I am attempting to apply a gradient effect on a Unity3D(5.2) gui object but its as if one of the gradient color keys is being completely ignored. I have tried with both instantiating a new gradient field and declaring a gradient field public and edit its keys in the editor but yet the effects remain the same.
I'm beginning to think that I am not supposed to use Gradients in a BaseMeshEffect in the way I am using it. If only have 2 keys, the colors render properly. Where am I wrong?
Here is a code sample followed by a screen shot.
public class GradientUI : BaseMeshEffect
{
[SerializeField]
public Gradient Grad;
public override void ModifyMesh(VertexHelper vh)
{
if (!IsActive())
{
return;
}
List<UIVertex> vertexList = new List<UIVertex>();
vh.GetUIVertexStream(vertexList);
ModifyVertices(vertexList);
vh.Clear();
vh.AddUIVertexTriangleStream(vertexList);
}
void ModifyVertices(List<UIVertex> vertexList)
{
int count = vertexList.Count;
float bottomY = vertexList[0].position.y;
float topY = vertexList[0].position.y;
for (int i = 1; i < count; i++)
{
float y = vertexList[i].position.y;
if (y > topY)
{
topY = y;
}
else if (y < bottomY)
{
bottomY = y;
}
}
float uiElementHeight = topY - bottomY;
for (int i = 0; i < count; i++)
{
UIVertex uiVertex = vertexList[i];
float percentage = (uiVertex.position.y - bottomY) / uiElementHeight;
// Debug.Log(percentage);
Color col = Grad.Evaluate(percentage);
uiVertex.color = col;
vertexList[i] = uiVertex;
Debug.Log(uiVertex.position);
}
}
Screen shot
Your script is actually OK, no problem with it. The problem here is that UI elements simply don't have enough geometry for you to actually see the whole gradient.
Let me explain. In a nutshell, each UI element is actually a mesh made of several 3D triangles, each one rotated to face the camera exactly with its front so it looks 2D. You filter works by assigning a color value to each vertex of those triangles. The color values in the middle of triangles are interpolated based on the proximity to each of the colored vertices.
If you look at UI element in wireframe, you will see that its geometry is very simple. This is for example how a sliced image looks:
As you can see, all of its vertices are concentrated at the corners, and there are no vertices in the middle. So, lets assume your gradient is 2 keys WHITE=>RED. The upper vertices get value WHITE or close to WHITE, the bottom values get value RED or close to RED. This works OK for 2 keys.
Now assume you have 3 keys WHITE=>BLUE=>RED. The upper value is WHITE or close to WHITE, the bottom values get value RED or close to RED, the BLUE value is supposed to be somewhere in the middle, but there is no vertex in the middle, so it is not assigned to anything. So you still get WHITE to RED gradient.
Now, what you can do:
1) You can add some more geometry programmatically, for example by simply subdividing the whole mesh. This may help you: http://answers.unity3d.com/questions/259127/does-anyone-have-any-code-to-subdivide-a-mesh-and.html. Pay attention that in this case, the more keys your gradient has, the more subdivisions are required.
2) Use texture that looks like a gradient gradient.