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]);
}
}
Related
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 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.
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.
Im finishing up my asset that I'm putting on the asset store. Right now one of the features require the average color of the sprite. Right now I have a public Color to find the average color, where the user can use the color picker or the color wheel or whatever to choose what they think looks like the average color of the sprite. I want to make it so the script automatically calculates the average sprite color, therefore increasing the accuracy by removing human error and increasing the efficiency by not wasting the users time guessing the average sprite color.
Well there is a post about it in Unity forums. Here the link. And the answer is:
Color32 AverageColorFromTexture(Texture2D tex)
{
Color32[] texColors = tex.GetPixels32();
int total = texColors.Length;
float r = 0;
float g = 0;
float b = 0;
for(int i = 0; i < total; i++)
{
r += texColors[i].r;
g += texColors[i].g;
b += texColors[i].b;
}
return new Color32((byte)(r / total) , (byte)(g / total) , (byte)(b / total) , 0);
}
I'm implementing the drag and drop in Libgdx with DragAndDrop class.
The actors that i have to move are in a grid (Table), centered in the screen.
The drag and drop starts if i click on the top-right corner of the screen, and not if i click on the actor itself! I can't figure out where is the problem.
This grid is a matrix:
for(int i = 0; i < Constants.ROWS; i++) {
for(int j = 0; j < Constants.COLS; j++) {
slots[i][j] = new Slot(Item.EMPTY, i, j);
}
}
Then i use the code above to create the table:
public class SlotsAreaActor extends Table {
public SlotsAreaActor(SlotsArea slotsArea, DragAndDrop dnd) {
// set the position of this actor in the screen
setPosition(Constants.SLOTS_AREA_ACTOR_X, Constants.SLOTS_AREA_ACTOR_Y);
// spaces all the row and the columns
defaults().space(Constants.ROWS_SPACE);
row().fill().expandX();
Slot[][] slots = slotsArea.getSlots();
for(int i = 0; i < slots.length; i++) {
for(int j = 0; j < slots[0].length; j++) {
SlotActor slotActor = new SlotActor(slots[i][j]);
dnd.addSource(new SlotSource(slotActor));
dnd.addTarget(new SlotTarget(slotActor));
add(slotActor);
}
row();
}
}
}
In the SlotActor class i set the bounds:
x = Constants.APP_WIDTH - Constants.ORIZONTAL_OFFSET - (Constants.TILE_SIZE * (Constants.COLS - slot.getX()));
y = Constants.APP_HEIGHT - Constants.VERTICAL_OFFSET - (Constants.TILE_SIZE * (Constants.ROWS - slot.getY()));
setBounds(x, y, Constants.TILE_SIZE, Constants.TILE_SIZE);
My formulas are wrong someway...
The Slot object holds its x (i, row) in the matrix, and y (j, column) in the matrix.
The Actor object holds the slot, and calculates its position in the screen with the formulas above.
Another question: what are float x and float y in the dragStart method?
UPDATE
The correct formula for y is:
y = Constants.APP_HEIGHT - Constants.VERTICAL_OFFSET - (Constants.TILE_SIZE * slot.getX());
But the dragStart still does not work. It is totally out of phase.
The dragging does not start when i click on the actor, but if i click on an area in the top-right corner of the screen.
UPDATE 2
The problem is the positioning of the Table. It is totally messed up.
UPDATE 3
With table.setDebug(true) i verified that the table is at the correct position. So... i really don't know what is happening.
For drag and drop i implemented as follows:
myActor.addListener(new DragListener(){
public void touchDragged(InputEvent event, float x, float y, int pointer){
myActor.moveBy(x-firstItem.getWidth()/2,y-firstItem.getHeight()/2);}});