JavaFX: prevent shape from dragging over another shape - java

I am doing a JavaFX application and I have a board with multiple shape (circles and rectangle) added to a Pane. I don't want circle to be moved accross rectangle.
Circle are allowed to be dragged using Mouse Event (OnMousePressed,Dragged,Released) while rectangle are not allowed to move.
I am using this code to detect when my circle are colliding with the rectangles.
private void checkIntersection(Shape block) {
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
}
}
}
if (collisionDetected) {
System.out.println("Collision detected");
} else {
System.out.println("Collision non deteted");
}
}
What I need to do is make my rectangle impossible to drag over while dragging circles. I don't want to send the shape back to his initial location.
Is there a way to do this using intersect or am I missing something?

It's not so easy to answer. You can have a class for instance GameObject. This class contains your Shape. In this GameObject class you have your drag&drop logic. Then u will have a class GameObjectManager which contains list of all GameObjects. And every instance of GameObject will have a reference to this GameObjectManager so knows about all GameObjects as well. So in your move logic you can check if there is some collision between specific GameObject types and if, u can stop moving.
For collision assessment class GameObject contains method like:
protected boolean isInCollision() {
for (GameObject gameObject : gameObjectManager.getAllGameObjects()) {
if (!gameObject.equals(this)) {
if (getView().getBoundsInParent().intersects(gameObject.getView().getBoundsInParent())) {
return true;
}
}
}
return false;
}
In your case you need to loop just some types of objects in this isInCollision method.

Just wanted to share my solution.
I wanted to check the node before the movement was done. So I modified the previous solution, to create the following.
Node Class: I am working with a custom Node class that extends Label. The methods used here are those inherited from Label.
private boolean hasNoCollision(Node dragged, double x, double y) {
// For each node
for (Node n : nodes) {
// If it is not the same, and future position overlaps
if (!n.equals(dragged) &&
n.getBoundsInParent().intersects(x, y, dragged.getWidth(), dragged.getHeight())) {
// Then prevent collission
return false;
}
}
// Otherwise all is good!
return true;
}

Related

How to access a getter from an object of a LinkedList

Following Scenario:
Classes:
GamePlayScene (Game logic and collision detection)
Obstacle (has the Rect getObstacleBounds() method to return Bounds)
ObstacleManager (has the LinkedList of obstacle objects)
I want to access the Boundaries (an android.Rect) of an obstacle. All obstacles will be stored into a LinkedList.
Now in the running game I want to access the getObstacleBounds() method in my GameplayScene Class but the problem is that I can't access the obstacle object directly but I obviously have to cycle through all my Objects in the LinkedList in my ObstacleManager.
Due to that I thought I have to also implement a Rect getObstacleBounds() in my Obstacle Manager, from where I cycle through every obstacle in my List and return that Rect.
Is this the right way to do so? I am fairly new to accessing objects and their methods in a LinkedList
If not: How would I implement access to such methods?
Here is my idea what I thought cold work / be the right way.
(Not compilable, more or less pseudo code)
GameplayScene.java
private ObstacleManager obstacleManager;
public GameplayScene() {
obstacleManager = new ObstacleManager();
obstacleManager.addObstacle(new Obstacle(...));
}
public void hitDetection() {
//get the Boundaries of obstacle(s) for collision detection
}
Obstacle.java
//...
public Rect getObstacleBounds() {
return obstacleBounds;
}
ObstacleManager.java
LinkedList<Obstacle> obstacles = new LinkedList<>();
public void update() { //example method
for (Obstacle o : obstacles){
o.update();
}
}
public Rect getObjectBounds() {
return ...
//how do I cycle through my objects and return each Bounds Rect?
}
In the end, depends of what you want to do in hitDetection
If you just want to check if a hit happened
In this case, you can just receive the list of Rect and check if any hit happened
GameplayScene.java
public void hitDetection() {
ArrayList<Rect> listOfBounds = obstacleManager.getObstacleBounds();
for(Rect bound : listOfBounds) {
// Do you stuff
// Note the here, you are receiving a list of Rects only.
// So, you can only check if a hit happened.. but you can't update the Obstacles because here, you don't have access to them.
// Nothing stops you of receiving the whole list of items if you want to(like the reference of ObstacleManager.obstacles).
}
}
ObstacleManager.java
public ArrayList<Rect> getObjectBounds() {
// You can also return just an array.. like Rect[] listToReturn etc
ArrayList<Rect> listToReturn = new ArrayList(obstacles.size());
for (Obstacle item : obstacles) {
listToReturn.add(item.getObjectBounds);
}
return listToReturn;
}
If you need to update some info on the Obstacle that was hit
In this case, you can transfer the hitDetection logic to you ObstacleManager (I'm assuming you check coordinates X and Y to check if obstacle was hit):
GameplayScene.java
public void hitDetection(int touchX, int touchY) {
Obstacle objectHit = obstacleManager.getObstacleTouched(int touchX, int touchY);
if (objectHit != null) {
objectHit.doStuffAlpha();
objectHit.doStuffBeta();
} else {
// No obstacle was hit.. Nothing to do
}
}
ObstacleManager.java
public Obstacle getObstacleTouched(int touchX, int touchY) {
Obstacle obstacleToReturn = null;
for (Obstacle item : obstacles) {
if(item.wasHit(touchX, touchY) {
obstacleToReturn = item;
break;
}
}
return listToReturn;
}
There are several ways to achieve what you want. Some better than others etcIn the end, depends of what you want to do exactly.

List copies final element to all other elements when converting from image to GameObject

I am working on a small project using Java and Swing. I'm making a very, very small and simple RPG that is in the style of Earthbound for mainly it's combat style. Alongside this project, I'm working on a framework to make it easier to create games of a similar genre and feel (i.e. screen, game loop, state manager, audio manager, etc). The issue I'm running into is that the "image to game object" converter class I made is overwriting the list with the final game object that is created. I am converting from a PNG to a GameObject (class created within the framework).
I diagnosed this by printing out the position and type of all the elements in the list to receive the same X, Y, and types for each element. I checked to make sure the HashMap I passed through was setup correctly and that each tile type was added correctly. Below is the relevant section of code to the top along with it's output:
private void init() {
tileMap.put(new Color(0,255,0), new Tile(16,16, TileType.GRASS));
tileMap.put(new Color(250,255,0), new Tile(16,16, TileType.SAND));
tileMap.put(new Color(135,135,135), new Tile(16,16, TileType.ROCK));
tileMap.put(new Color(255,0,233), new Tile(16,16, TileType.DIRT_PATH_SIDE));
for(Color t : tileMap.keySet()) {
System.out.println(((Tile) tileMap.get(t)).getTileType());
}
....
}
----- OUTPUT -----
GRASS
ROCK
DIRT_PATH_SIDE
SAND
The image loads correctly and the HashMap's values are added correctly so I decided to see where in the framework the issue was. I checked the position when it was being set and it was fine (ie (0,0), (0,16), (0,32)...) until I looped through the finished list where the game objects in the list are all the same.
I know that static variables cause an issue but the only "static" variable I am using is the enums to denote what the tile type is. I used an integer just to see what would happened and yielded the same result. I took the final list, made it a variable the class could read as opposed to just the function, and tried to see if that would work but still was just the final game object created after reading.
I've checked over SO and other websites but nothing is working. I fear that I looked at this problem the wrong way as I was trying to implement a solution I used in Unity/C# here but probably had a disconnect somewhere along the way.
Here is the full function from earlier:
private void init() {
tileMap.put(new Color(0,255,0), new Tile(16,16, TileType.GRASS));
tileMap.put(new Color(250,255,0), new Tile(16,16, TileType.SAND));
tileMap.put(new Color(135,135,135), new Tile(16,16, TileType.ROCK));
tileMap.put(new Color(255,0,233), new Tile(16,16, TileType.DIRT_PATH_SIDE));
for(Color t : tileMap.keySet()) {
System.out.println(((Tile) tileMap.get(t)).getTileType());
}
try {
im.loadImage();
} catch (IOException e) {
e.printStackTrace();
}
im.readImage(tileMap);
objects = im.getMap(); // objects is a list within the class that contains all Tile game objects.
}
And the converter class's relevant code:
public void readImage(HashMap<Color, GameObject> tileDict) {
for(int x=0; x<img.getWidth(); x++) {
for(int y=0; y<img.getHeight(); y++) {
GameObject g = determineObject(tileDict, x, y);
if(g != null) {
map.add(g);
}
}
}
}
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
for(Color c : tileDict.keySet()) {
if(c.getRGB() == img.getRGB(x, y)) {
g = tileDict.get(c);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
}
}
return g;
}
--- EDIT: 8/10/2017 ---
I am sorry for not clarifying what the structure looks like. GameObject is an abstract class within the framework I've made that is extended by Tile in the game. As well, TileType is an enum type that I created within the game and not the framework. The framework is in a separate jar/project so it is unaware of what extends GameObject and what TileType is.
--- EDIT 2: 8/10/2017 ---
I tried implementing a solution using the Serializableclass but that didn't work. I followed the example from this question. The copy() function I created in the abstract GameObject looks like this:
public final GameObject copy() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new ObjectOutputStream(baos).writeObject(this);
return (GameObject) new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();
} catch (Exception e) {
throw new AssertionError();
}
}
I have also tried this as an abstract method and wrote the function in Tile but there is no current result. I'll keep mucking around here to see if anything comes up.
Resources
Java ArrayList.add() replaces all elements in array with the final element
List overriding objects java [closed]
Add elements to Arraylist and it replaces all previous elements in Java [duplicate]
Why does my ArrayList contain N copies of the last item added to the list?
I think, the problem here is, that you get the GameObject from the map and then modify it. So if you get the same GameObject twice, it gets modified two times and also gets added to the list twice.
To have different GameObject's, you have to create a new one in determineObject().
BTW: it's very confusing to name a list map.
If I got it correctly tileMap is a static member of your class and you pass it to the readImage and thus to the determineObject method?!
In determineObject you change the xPos and yPos attributes of your objects in your static tile dictionary:
g = tileDict.get(c);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
That is you modify the attributes of an entry in the global map.
You will need to create a copy of the GameObject instance you get from the map and continue with the copy instead of modifying the original object. Your code should do something like this:
GameObject globalGameObject = tileDict.get(c);
g = globalGameObject.createCopy();
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
Where createCopy() is a new method that creates a copy of the current instance. Each implementation of GameObject has to implement this method:
public abstract class GameObject {
...
public abstract GameObject createCopy();
...
}
You could use the Cloneable feature of Java to create the copies for you as well, but Cloneable is easy to use wrong and I've actually not seen anyone using it for real life code till now.
Alright so I found out the issue. While doing research on dpr's and Claus Radloff's answers, I came across the solution here. Seeing as in my case I was using an abstract class, I could not do what both Claus and dpr recommended per-say as you can't instantiate an abstract class. In order to solve this, I made the abstract class implement the Serializable class as I said in my question. I created the abstract method GameObject copy(); which the objects extending from this can implement or ignore (return null). From here, only one line of code is required inside said method:
return new Tile(this.width, this.height, this.type);
A big thank you to those that guided me in the right direction! I apologize again for not clarifying my structure in my initial post.
I think your map should containe TileTypes instead of Tiles:
tileMap.put(new Color(0,255,0), TileType.GRASS);
tileMap.put(new Color(250,255,0), TileType.SAND);
tileMap.put(new Color(135,135,135), TileType.ROCK);
tileMap.put(new Color(255,0,233), TileType.DIRT_PATH_SIDE);
then method determineObject would become:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
for(Color c : tileDict.keySet()) {
if(c.getRGB() == img.getRGB(x, y)) {
TileType type = tileDict.get(c);
g = new Tile(x, y, type);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
// BTW, how about a break here?
}
}
return g;
}
Or even:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
Color c = new Color(img.getRGB(x, y));
TileType type = tileDict.get(c);
if (type != null) {
g = new Tile(x, y, type);
g.setXPos(x*g.getWidth());
g.setYPos(y*g.getHeight());
}
return g;
}
UPDATE
I forgot to multiply x and y by the tile width. With my approach, you cannot use g.getWidth() and g.getHeight(), but I think in your case their values are both 16. Ill will add constants:
private static final int TILE_WIDTH = 16;
private static final int TILE_HEIGHT = 16;
and the method determineObject becomes:
private GameObject determineObject(HashMap<Color, GameObject> tileDict,
int x, int y) {
GameObject g = null;
Color c = new Color(img.getRGB(x, y));
TileType type = tileDict.get(c);
if (type != null) {
g = new Tile(TILE_WIDTH, TILE_HEIGHT, type);
g.setXPos(x*TILE_WIDTH);
g.setYPos(y*TILE_HEIGHT);
}
return g;
}

Java: Checking rectangle collision against multiple objects

I've been learning Java by experimenting with a little "game" that started with just trying to make a ball jump. I've got 3 classes (JumpingBall3, BallSprite3, & Floor) and have achieved a gravity of some sorts, a jump that works consistently, and hit detection against floors to stop the ball falling infinitely. With this last point I've spotted a potential issue with future development. Right now I have two floors created by JumpingBall3 ("floor1" & "platform") and I detect collision within the BallSpite3 using the following code:
public boolean collision()
{
if (game.floor1.getBounds().intersects(getBounds()) || game.platform.getBounds().intersects(getBounds())) {
onFloor = true;
}
else
{
onFloor = false;
}
return onFloor;
}
If I were to keep adding more floors or platforms that "if" condition is quickly going to spiral out of control in terms of length. Is there a way to create a method that cycles through all visible Floor objects created in my JumpingBall3 class?
I've posted the full code online here, it seemed a bit lengthy to include within this post.
The simplest thing to do is to keep all the objects that you want to check in a Collection like for example a List, then iterate over this List.
So for example, here a good choice would be to use a collection of Floor, on which we iterate to check if we have a collision with one of them.
public boolean collision() {
boolean onFloor = false;
Rectangle rectangle = getBounds();
for (Floor floor : floors) {
if (floor.getBounds().intersects(rectangle)) {
onFloor = true;
break;
}
}
return onFloor;
}
Assuming that you use Java 8 , you could rely on the Stream API to do the same thing as next:
public boolean collision() {
Rectangle rectangle = getBounds();
return floors.stream().map(Floor::getBounds).anyMatch(rectangle::intersects);
}
An approachable solution to this problem is to have your "game world" contain a list of entities (where an entity can be a ball or wall or any other in game object), and have some mechanism that detects which entities are near which other entities. This would end up calling some type of entity.checkCollision(neighborEntity) method.
You still need to have different behaviors for colliding with different entities. You can do this by having the base Entity class have some common attributes you can turn off or on, or store behaviors that you can apply directly to the collided entity.
// within some game loop, check for collisions
for (Entity entity : collidableEntities)
{
ball.checkCollision(entity);
}
Your classes could look like this to have programmed behaviors.
public Entity
{
public void applyCollisionBehaviorTo(Ball ball) { // Override to do something}
public void onCollision() { // Override to do something }
public collidesWith(Entity neighbor) { // your collision math }
public void checkCollision(Entity neighbor)
{
if (collidesWith(neighbor))
{
onCollision()
}
}
}
public Wall extends Entity
{
#Overide
public void applyCollisionBehaviorTo(Ball ball)
{
ball.reverseDirection();
}
}
public Ball extends Entity
{
#Overide
public void onCollision(Entity collidingEntity)
{
collidingEntity.applyCollisionBehaviorTo(this);
}
}
create a list with all objects. then use a loop over all the object you want to detect (excepting the one that making the detection of course)

Turn Based Game Java(Stratego)

so i have JXButton[][] array (gridLayout) and each JXButton holds an icon, a piece,which player belongs to and has a mouseListener.
I am currently trying to make the Stratego Game(Two Players-I handle both).
I set up the icons,pieces and how a piece should move alright.
Now i wish to make it play by turn.
For example when is Player1 Turn i need all Players2' pieces to change icon to Hidden(hidden.png) and vice versa.
I have tried something like this.
tmp1, tmp2 are Icon arrays
pieceimgsB,R hold the Hidden Icon
allbuttons is my JXButton[][] array
public void makeHidden(int iD){
if(iD==1){
for (int i=0;i<8;i++){
for(int y=0;y<10;y++){
if(allbuttons[i][y].getPlayerID()==iD){
tmp1[i][y]=allbuttons[i][y].getIcon();
allbuttons[i][y].setIcon(new ImageIcon(pieceimgsB[12]));
}
}
}
}
else if(iD==2){
for (int i=0;i<8;i++){
for(int y=0;y<10;y++){
if(allbuttons[i][y].getPlayerID()==iD){
tmp2[i][y]=allbuttons[i][y].getIcon();
allbuttons[i][y].setIcon(new ImageIcon(pieceimgsR[12]));
}
}
}
}
}
public void restoreHidden(int iD){
if(iD==1){
for (int i=0;i<8;i++){
for(int y=0;y<10;y++){
if(allbuttons[i][y].getPlayerID()==iD){
allbuttons[i][y].setIcon(tmp1[i][y]);
}
}
}
}
else if(iD==2){
for (int i=0;i<8;i++){
for(int y=0;y<10;y++){
if(allbuttons[i][y].getPlayerID()==iD){
allbuttons[i][y].setIcon(tmp2[i][y]);
}
}
}
}
}
I my mind makeHidden Player2 pieces hidden when its Players1 turn.
And restoreHidden should change back the Icons when its Players2 turn.
If these two methods seem ok , where my problem lies is how to implement the turns.
I must say that (When i click on a JXButton and then click on another one, the
piece moves on the board as it should). I tried having a flag in my mouseListener that when one actually moves the turn changes, but i cant make it work by turns.
I have wrote this :
public void letsPlay(){
switch (turn){
case 1:
getsb().makeHidden(2);
//getsb().restoreHidden(1);
if(getsb().getPlayerMoved()==true){
setTurn(2);
}
break;
case 2:
getsb().makeHidden(1);
//getsb().restoreHidden(2);
if(getsb().getPlayerMoved()==true){
setTurn(1);
//;
}
break;
}
}
I need to know if these two methods seem ok according to what they should do and a little insight on how to get it to work by turns.
Should i have the getPlayerMoved() (which returns the flag in the mouseListener in a while outside the switch case)?
Maybe i am tired and i dont see it but any insight would be helpful.
If someone needs it i can provide my mouseListener Code too although its a bit messy.
This seems to be an XY problem, the main point is not to specialize your listener to manage such behavior (and other inherent behaviors) but how to design something that is modular and easily maintainable.
I'd suggest you to try to workaround your problem by thinking how you could design your game and UI structure. Let's make a simple example:
First of all you have a game piece which has a type and a player, so why don't you use a specific object type for this? Eg:
class PieceType {
String name;
String iconName;
}
class Player {
String name;
}
class Piece {
PieceType type;
Player owner;
class BoardCell {
Piece piece;
}
Then you surely need a Board class able to manage the game board, eg:
class Board {
private BoardCell [][] pieces = new Piece[10][10];
public BoardCell cellAtPiece(int x, int y) { return pieces[x][y]; }
/* other functions */
}
Finally you should have a Game class which manages the whole thing, eg:
class Game {
Board board;
Player[] players = new Player[2];
Player currentPlayer;
Player getCurrentPlayer() { return currentPlayer; }
/* other methods, eg turn advance, check for correct position, eat piece etc */
}
Now you reached a point in which you have the structure of the game, and you can think about the UI, which should rely on the Game instance without the need of additional inputs (and Game shouldn't even know about the UI). You could extend a JXButton and provide custom behavior, eg:
class BoardButton extends JXButton {
final private Game game;
final private BoardCell cell;
public BoardButton(Game game, int x, int y) {
this.game = game;
this.cell = game.cellAtPiece(x,y);
}
public void refreshIcon() {
if (cell.piece == null) { setIcon(null); }
else if (cell.piece.owner != game.getCurrentPlayer()) { setIcon(hidden); }
else setIcon(cell.piece.type.icon);
}
/* other utilities, like checking if a piece can be moved from here for current player and such */
Mind, I didn't answer directly to your question, but I explained some tools which would allow it to be solved easily together with all problems that you could find in implementation.

How to change color and stroke of one type of edges

I have a Graph< Potter, Edge> g where Edges belongs to three different classes that extends the Edge class (I use it to represent different type of interactions, like begin related, ask advices and so on...). I would like to color edges accordingly to what they represent, like having all Parental edges turn green and not display arrows. I have this transformer to change color, but it appears to change colors to all the edges:
Transformer<Edge, Paint> parental_color_yes = new Transformer<Edge, Paint>() {
#Override
public Paint transform(Edge s) {
return Color.GREEN;
}
};
If I change the type of the transformer to Transformer< Parental, Paint>, then my VisualizationViewer< Potter, Edge> vv complains that cannot accept such a transformer... should I add a new visualization viewer? or there is something wrong in the transformer?
EDITED after the reply:
parental_color_yes = new Transformer<Edge, Paint>() {
#Override
public Paint transform(Edge s) {
if (s instanceof Parental){
return Color.GREEN;
} else if (s instanceof Innovation) {
return Color.RED;
} else {
return Color.BLACK;
}
}
};
Thank you for the help!
Best regards,
Simone
It needs to be an Edge-Paint Transformer. Inside the transform method, use an instanceof check to see what color to return.

Categories

Resources