I'm having a problem with checking the colision of objects painted on the screen. For example: I'm currently making a snake game and I have to make it check whether the snake is hitting a certain block object ( which makes the snake increase and increases the score when the snake hits/'eats' the block ). So I made a function to check the collision between the snake and the block object but it doesn't work correctly ( when moving over the object with the snake from right above, it does work, but otherwise it does not ):
public boolean checkColision() {
if(SnakeObjs.get(0).x >= obj.x && SnakeObjs.get(0).x
<= obj.x+10 && SnakeObjs.get(0).y
>= obj.y && SnakeObjs.get(0).y <= obj.y+10) {
return true;
}else{
return false;
}
}
This function checks the collision. Where SnakeObjs.get(0) contains the x and y choords of the snake object that needs to hit the block object and the obj contains the x and y coordinates of the block object to check the collision with.
The paint method, painting both the block object and the snake object, looks like this:
public void paint(Graphics g) {
for(int i=0;i<SnakeObjs.size();i++) {
g.setColor(new Color(
(int)((double)Math.random()*200.0),
(int)((double)Math.random()*200.0),
(int)((double)Math.random()*200.0)));
g.fillRect(SnakeObjs.get(i).x, SnakeObjs.get(i).y, 10, 10);
g.setColor(Color.WHITE);
g.drawRect(SnakeObjs.get(i).x-1, SnakeObjs.get(i).y-1, 12, 12);
}
g.setColor(new Color(
(int)((double)Math.random()*200.0),
(int)((double)Math.random()*200.0),
(int)((double)Math.random()*200.0)));
g.fillRect(obj.x, obj.y, 10, 10);
g.setColor(Color.BLACK);
g.drawString("Score: "+score, 10, 10);
}
If anyone can help me out on this collision problem it would be great.
Thanks in advance,
Best Regards,
Skyfe.
The mistake is that you interpret one object as rectangle and the other as point. You check if the point is in the rectangle and not if the both rectangle intersect. That it work from right and from top.
I recommended to save an rectangle for the snake and the object. Ad a method getBounds(). then you can use the method intersect() from Rectangle. You can also use this bounds for your draw operation.
Related
I am creating a game using Java Swing and Graphics in which I need to sense when the player comes into contact with some obstacles. I am trying to compare when their hitboxes overlap but it seems for some obstacles the exact boxes I see on the screen don't compare exactly to coordinates being compared between player and object. They are close but not exact. Therefore, if the player is slightly to the right or left of the object he will sometimes act as though he touched it even though the hitboxes do not visually overlap. The printed out coordinates show they overlap even though this is not what is shown on screen. I can fix this by adding a "wobble" to the inequalities I am comparing, a relatively small, hard coded value which I have to figure out and is not that precise. Is this an issue with Graphics just not being that exact? Is there a way to fix this?
public boolean isTouching(Player p)
{
if (p.getX()<this.getXHitBox()+this.getWHitBox() && p.getX()+p.getWidth()>=this.getXHitBox() && p.getY()+p.getHeight()>this.getYHitBox() && p.getY()<=this.getYHitBox()+this.getHHitBox())
{
//some stuff
return true;
}
return false;
}
XhitBox is the x value of the hitbox (x + xOffset)
YHitBox is the y value (y+yOffset)
HHitBox is the height value
WHitBox is the width value
hitbox is set for obstacles as such:
hitbox=new Rectangle2D.Float( (float) (x + xOffset), (float) (y + yOffset), w, h);
and drawn like this:
public void drawHitbox(Graphics g)
{
g.setColor(Color.RED);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(hitbox);
}
I expected the sensing to only occur when the hitbox visually overlapped but the hitboxes are just slightly off (wobble= approx. 15) from reality. Why is that?
I tried printing out the coordinates and they are different from what is shown on screen! Even if the player is still slightly more to the right than the obstacle, according to the coordinates he is a little more to the left and touching the obstacle.
ie Obstacle will be to the left with x coordinates 88 (for x + width)
Player will be slightly to the right of the obstacle with coordinates 77. What gives?
I have an if statement which checks for collision as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
}
I have a for loop inside this if statement as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
for (int i=50; i<width; i+=80)
{
fill(250,0,0);
ellipse(i, 50, 70, 70);
}
}
So the point is to draw a line of circles on the top of the screen once the collision occurs. This code however, only draws them for a split second then they disappear. How would I make them stay given that a collision has occurred?
You might want to use a boolean value that tracks whether the ball has collided. Set it to true when you detect a collision, and then check the value to decide what to draw. Here's a simplified example:
boolean drawRed = false;
void draw() {
if (mouseY > height/2) {
drawRed = true;
}
if (drawRed) {
background(255, 0, 0);
}
}
This code draws a gray background by default, but then turns to red if the mouse goes in the lower half of the window. It stays red even if you move the mouse back to the top part.
This is just a simple example, but the idea is the same: use a variable to track the state of the sketch, set that variable when your condition is met, and check that variable to decide what to draw.
By the way, your collision detection is a little bit suspicious. You probably don't want to check whether the ball is at an exact location. Instead you probably want to check whether the ball overlaps some area. Here is a guide on collision detection in Processing that might be useful.
If you still can't get it working, please narrow your problem down to a MCVE instead of posting disconnected snippets or your full sketch. Good luck!
A LinearGradientPaint object from java.awt may appear nice once painted, but there's a problem I'm having with it for painting an animated background in some kind of game model that's taking me long to build.
I want to paint an animated rainbow gradient on the background using the Graphics2D paint object, except that when I do so, I notice a lot of lag in repainting the panel. It should repaint itself at least 30 frames per second, which is only possible if the Paint object the graphics object uses is not a rainbow gradient.
Even running it as a separate thread will not do the trick. Below is the code for what I am trying to do at the end of each frame:
gamePanel.executor.execute(new Runnable(){
public void run()
{
while(true)
{
if (Background.selectedBackgroundIndex >= Background.SKY_HORIZON_GRADIENT_PAINT &&
Background.selectedBackgroundIndex < Background.SPACE_PAINT)
{
float displacementValue = 1.0f;
if (Background.backgroundShape.y < ((-2990.0f) + CannonShooterModel.gamePanel.getSize().height) && gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = false;
else if (Background.backgroundShape.y > (-10.0f) && !gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = true;
Point2D.Double startPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getStartPoint()),
endPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getEndPoint());
if (gamePanel.horizonGoingDown)
Background.backgroundShape.y -= displacementValue;
else
Background.backgroundShape.y += displacementValue;
startPoint.setLocation(0, Background.backgroundShape.y);
endPoint.setLocation(0, Background.horizonGradientPaintHeight + Background.backgroundShape.y);
// Should be done in another thread, particularly in arithmetic calculations.
Background.background = new LinearGradientPaint(startPoint, endPoint,
((LinearGradientPaint)Background.background).getFractions(),
((LinearGradientPaint)Background.background).getColors());
}
for (int a = 0; a < PlayerUnit.weapon.bullets.length; a++)
{
if (PlayerUnit.weapon.bullets[a] != null)
{
if (PlayerUnit.weapon instanceof Pistol &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0 &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x <= CannonShooterModel.gamePanel.getSize().width &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0)
{
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x +=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x -=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y -=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y +=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
}
else
PlayerUnit.weapon.bullets[a] = null;
}
}
//System.out.println(Background.backgroundShape.y);
repaint();
try
{
Thread.sleep(1000 / 60);
}
catch (InterruptedException ex)
{
}
}
}
});
The classes Background, PlayerUnit, and CannonShooterModel are important to my game model. It's an upright shooting game supposed to be designed with various weapons and enemies.
This rainbow gradient I have uses an array of eight different Color objects. For every frame passed through, I change the y-coordinate for both Point2D.Float objects required for the gradient paint as desired. In order for the animation to work, I have to actually instantiate another object of LinearGradientPaint again, with some of the previous properties from the previous object, and have it be referenced by the variable background of type Paint.
Problem is, LinearGradientPaint does not have a method to where you can do a translate on the two end points, and the get methods do not return the actual object that LinearGradientPaint object contains. (what I mean is, the get methods return a new object of Point2D with the same values as those part of the LinearGradientPaint object.)
For every frame passed, I have to change not only the y-coordinate property of the shape that's associated with the gradient, but also set the locations of the two Point2D objects that are needed to instantiate LinearGradientPaint once again.
I would love to re-explain this much simpler, because I can have trouble with some knowledge of English, even though this is my primary language. Please let me know if you need re-explanation.
There are a couple of solutions you might try.
Instead of filling the entire paintable area, you could create a BufferedImage whose width is 1 pixel and height equal to the area you want to fill (assuming you are fill vertically). You would then apply the LinearGradientPaint to this BufferedImage's Graphics2D and fill it (don't forget to dispose of the Graphics context when your done).
Then, you would simply use Graphics#drawImage(Image, x, y, width, height, ImageObserver) to actually paint the image. Generally speaking, it appears that it's faster to rescale an image then it is to fill it with a LinearGradientPaint, especially when you consider you are only stretching the image horizontally.
The other choice would be to generate a basic BufferedImage which had the LinearGradientPaint already applied and you would simply paint this offset as required. This would probably require you to paint it at least twice to allow it to "stitch" toegther...
If you are just making the background gradient move up and down, could you write it to an image at initialization and then move and wrap the image vertically?
I have a Game Tutorial that I followed, that paints String's on the Screen using Graphics2D. It works like a star, but the only problem is that I don't undertstand why.
I call draw(graphics) in a game loop and it works fine. I use an int, named currentChoice to keep track of which letter should be Red and which should be Black.
Well, I call the method Draw in a loop. I just don't understand how does the graphics clear the previous string it drew. I mean, I call the method constantly, and it keeps on Drawing string's on the window, and its 'clearing' the other ones (if you get what i'm saying).
Basicly, I just don't undertstant how it's clearing the screen (NOTE: I am super new to this sort of thing)
CODE (I call this in a loop and it works):
public void draw(Graphics2D graphics) {
bg.draw(graphics);
graphics.setColor(titleColor);
graphics.setFont(titleFont);
graphics.drawString("Peache's Revenge", 50, 70);
graphics.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == currentChoice) {
graphics.setColor(Color.RED);
} else {
graphics.setColor(Color.BLACK);
}
graphics.drawString(options[i], 145, 140 + i * 15);
}
}
Assuming the Graphics context does not change (ie is the same for each call), then, unless the background is cleared, content will continue to be painted ontop of it.
From you comments, bg.draw is drawing the background, over the top of whatever was previously painted, meaning that anything that was previously painted will now be covered by the background, thus requiring the text to be re-generated.
I'm trying to code a GUI that allows the user to move a box around. There is also another box on the screen, called "block" that the box isn't allowed to intersect. I have box moving fine, but I don't know how to stop the two from intersecting and keep the drawing of the box on the screen. Right now, the box disappear when it hits the block (I know why it's doing this, I just don't know how to fix it).
X and Y are the movement detected by the left and right mouse keys.
box = new Rectangle2D.Double(0 + X, 0 + Y, 200, 50);
block = new Rectangle2D.Double(300, 300, 50, 50);
if (box.intersects(block)) {
hit = true;
} else {
hit = false;
}
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.red);
g2.draw(block);
if (model.hit()) {
g2.setPaint(Color.black);
g2.drawString("WHOA THERE", 20, 50);
} else {
g2.setPaint(Color.blue);
g2.fill(box);
I'm a little unclear on what you're asking. If you're asking how to draw the box when it hits the block, the problem is your if/else statement. In the if case, it skips the drawing block. Remove the else to draw the box even if it hits.
If you're asking how to prevent the two boxes from intersecting, that's easy. If you detect they intersect, move the moving box so it's just outside the block. So if the block is at x = 10, set the moving box (model?) so it's at x = 11. HTH