Java Slick2d - how to keep a shape allways inside a window? - java

I'm moving a circle across the window by dragging it with the mouse. I'm supposed to make it always inside the window.
So by the default, when you drag the circle in a way that your mouse exits the frame, half of the circle will disappear (because it exits the frame), and half of it won't. I need to make it visible whole all the time, even if your cursor exits the frame. Here's the code:
if(draggingcircle)
{
g.drawString("Dragging circle = " + draggingcircle, 50, 110);
circle.setCenterX( gc.getInput().getMouseX() );
circle.setCenterY( gc.getInput().getMouseY() );
}

whatever the circle is contained in, lets call id , you can keep it in the container with simple math if you know the radius or the diameter (i forget which)
so
if(draggingcircle)
{
g.drawString("Dragging circle = " + draggingcircle, 50, 110);
circle.setCenterX( gc.getInput().getMouseX() );
circle.setCenterY( gc.getInput().getMouseY() );
}
becomes
var width = $('#container').width();
var height = $('#container').height();
var radius = 2;
if(draggingcircle)
{
g.drawString("Dragging circle = " + draggingcircle, 50, 110);
if (gc.getInput().getMouseX() > radius && gc.getInput().getMouseX() < width - radius)
{
circle.setCenterX( gc.getInput().getMouseX() );
}
if (gc.getInput().getMouseY() > radius && gc.getInput().getMouseY() < height - radius)
{
circle.setCenterY( gc.getInput().getMouseY() );
}
}
Sorry for my poor syntax, I am not familiar with Slick2d, but something along these lines should work.

Related

How to make images of objects drag and droppable in Java Processing

I am trying to make a image that was loaded into processing be able to move along with the click of the mouse, and dropped when the mouse is let go.
I am new to Processing and am learning everything I can off the Internet. I am trying to make a image, that was loaded into Processing, be able to move along with the click of the mouse and dropped when the mouse is let go.
I have done this with a shape, but I don't know the how to do it with images. I am completely new to java Processing so I don't really know what I am doing so if you go through each step individually please.
Here is the code. It is a mess:
PImage scene, can;
int can_x, can_y, can_count;
float squareX = 200;
float squareY = 200;
float squareWidth = 50;
float squareHeight = 50;
//keep track of when the mouse is inside the square
boolean mouseInSquare = false;
boolean mouseInCan = false;
void setup() {
size(800,600,P2D);
scene = loadImage("backround.png"); // load image and data into scene data structure
can = loadImage("can.png"); // load image of rain drop into the GPU
textureMode(NORMAL); // Scale texture Top right (0,0) to (1,1)
blendMode(BLEND); // States how to mix a new image with the one behind it
noStroke(); // Do not draw a line around objects
can_x=0+(int)random(800); // Choose drop starting position
can_y=0;
}
//check if the mouse is in the square
void mousePressed() {
if (mouseX > squareX && mouseX < squareX + squareWidth && mouseY > squareY && mouseY < squareY + squareHeight) {
mouseInSquare = true;
}
}
//void mousePressed() {
//if (mouseX > can_x && mouseX < can_x + mouseY > can_y && mouseY < can_y) {
// mouseInCan = true;
//}
//}
//if the mouse is in the square, then move it when the mouse is dragged
void mouseDragged() {
if (mouseInSquare) {
float deltaX = mouseX - pmouseX;
float deltaY = mouseY - pmouseY;
squareX += deltaX;
squareY += deltaY;
}
}
//when we let go of the mouse, stop dragging the square
void mouseReleased() {
mouseInSquare = false;
}
//draw the square
void draw() {
background(scene);
image(can, 0, 0);
rect(squareX, squareY, squareWidth, squareHeight);
pushMatrix(); // Store current location of origin (0,0)
translate(can_x,can_y); // Change origin (0,0) for drawing to (drop_x,drop_y)
beginShape(); // Open graphics pipeline
texture(can); // Tell GPU to use drop to texture the polygon
vertex( -20, -20, 0, 0); // Load vertex data (x,y) and (U,V) texture data into GPU
vertex(20, -20, 1, 0); // Square centred on (0,0) of width 40 and height 40
vertex(20, 20, 1, 1); // Textured with an image of a drop
vertex( -20, 20, 0, 1);
endShape(CLOSE); // Tell GPU you have loaded shape into memory.
popMatrix();
can_y+=1.5; // Make "drop" move down the screen (two pixels at a time)
if(can_y>600) // If y value is entering the bottom of screen
{
can_x=0+(int)random(800); // Restart the drop again in the cloud.
can_y=0;
}
}
I know it's not organized as I was just trying different ways of trying to get it to work.

Graphics won't clear on a transparent JPanel

I am creating a blank transparent JPanel and then drawing lines to form boxes on it. I want to increase the size of the box but when I do I end up leaving a trail behind where the lines used to be.
I've done much searching online but can't seem to find a solution that works for me.
Any help would be much appreciated!
public class AVTBox extends JPanel {
private int boxSize = 100;
private boolean started = false, stopped = true, track = false;
private final int center = 150;
private final int maxBoxSize = 300, minBoxSize = 25;
private final int lockBoxSize = 30;
public AVTBox()
{
this.setOpaque(false);
this.repaint();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
g2.setStroke(new BasicStroke(3.0f));
g2.setColor(Color.BLACK);
g2.draw(new Line2D.Double(center - (boxSize/2), center - (boxSize/2) + (boxSize*0.3),
center - (boxSize/2), center + (boxSize/2) - (boxSize*0.3))
);
g2.draw(new Line2D.Double(center + (boxSize/2), center - (boxSize/2) + (boxSize*0.3),
center + (boxSize/2), center + (boxSize/2) - (boxSize*0.3))
);
g2.draw(new Line2D.Double(center - (boxSize/2) + (boxSize*0.3), center - (boxSize/2),
center + (boxSize/2) - (boxSize*0.3), center - (boxSize/2))
);
g2.draw(new Line2D.Double(center - (boxSize/2) + (boxSize*0.3), center + (boxSize/2),
center + (boxSize/2) - (boxSize*0.3), center + (boxSize/2))
);
g2.dispose();
}
public void setBoxSize(String change)
{
switch (change) {
case "add":
if(boxSize < maxBoxSize)
{
boxSize++;
} break;
case "sub":
if(boxSize > minBoxSize)
{
boxSize--;
} break;
}
this.revalidate();
this.repaint();
}
}
EDIT: Everything works as it should when the panel has a full non-transparent background but moving these lines on a transparent background leaves painted parts behind. I need to find a way of getting this 'animation' working on a transparent background.
This image shows what should happen when the user increases the box size (green arrow) and what happens at the moment (red arrow).
Sorry for the terrible MSpaint image!
So I figured it out; I was adding this JPanel to another JPanel instead of a JFrame. Not completely sure why but everything worked perfectly after being added directly to the JFrame.

Detecting ball collision with a user-added square

Basically I have been asked to create a pinball game that fires a ball on to a board and the user can control flippers etc to keep the ball from hitting an absorber with added shapes to act as bumpers to keep the ball in play.
However, I've run in to a little problem with my collisions. The user can click a grid square on the board to highlight it and then use the 'Add Square' button to add a square of height 20 and width 20 to that highlighted square also returning its (x,y) position.
public void addASquare(Point p) {
System.out.println("Add square to point: " + p.x + ", " + p.y);
Square square = new Square(p.x, p.y, L, L);
bumperList.add(square);
setChanged();
notifyObservers(bumperList);
}
Once, this has been done I then add Line Segments to the square using the (x,y) coordinates from the use adding the square to prepare for collision detection with a ball.
public ArrayList<LineSegment> getLineSeg() {
ArrayList<LineSegment> lines = new ArrayList<LineSegment>();
LineSegment l1 = new LineSegment(x, y, x + 1, y); // top
LineSegment l2 = new LineSegment(x, y + 1, x + 1, y + 1); // bottom
LineSegment l3 = new LineSegment(x, y, x, y + 1); // left
LineSegment l4 = new LineSegment(x + 1, y, x + 1, y + 1); // right
lines.add(l1);
lines.add(l2);
lines.add(l3);
lines.add(l4);
return lines;
}
..and here is the code for the collision detection when the ball hits either side of the square.
ArrayList<LineSegment> lseg = sq.getLineSeg();
for (LineSegment line : lseg) {
time = Geometry.timeUntilWallCollision(line, ball,
velocity);
if (time < minimumTime) {
minimumTime = time;
newVelocity = Geometry.reflectWall(line, ball.getVelocity(), 1.0);
return new CollisionDetails(minimumTime, newVelocity);
}
}
However, when I run the program the ball just carries on through the square. I think I am overlooking some key detail that I can't seem to solve which is why I'm here, so any help or pointers at all will be greatly appreciated.
You say your square has side lengths of 20 units which I suppose is the value of your constant L but your line segments only have a length of 1. Try replacing the values of 1 by your constant L.

How to draw a circle within a circle?

I'm trying to get a bunch of small circles that have varying shades of green to be drawn within a big circle to get a "bush" look, but I can't figure out how to get all the small circles within the shape of a big circle. I can only figure out how to get it within a rectangle.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i = 0; i < 1000; i++){
int redV = (int) ((Math.random() * 100) + 27);
g.setColor(new Color(red, red + 31, red - 15));
int x = (int) ((Math.random() * 400) + 150);
int y = (int) ((Math.random() * 500) + 200);
g.fillOval(x, y, 50, 50);
}
}
I guess you have to do some geometry here, and verify whether the x and y coordinates generated randomly are within your circle. As you said, within a rectangle is easy (because you just check that x > left, x+50 < right, y > top, y+50 < bottom), however for a circle you have to use the equation of a circle and check that (x,y) and (x+50,y+50) are within it before actually doing the fillOval().
I think you have a simple way out by using the Java 2D Shape.contains(), which is implemented by Ellipse2D. So essentially you create an instance of Ellipse2D.Double or Ellipse2D.Float for the greater circle, and then just call contains() each time you generate the coordinates to check they are within it before drawing them.
I think you can just change the Color slightly, and increment/decrement x, y, width, and height slightly to get them to be within the older circle. The new oval should be painted over the old one.
Choose the point that should be the center of the big circle, and draw the big circle relative to that (e.g. using java.awt.geom.Ellipse2D).
You can then use the center of the big circle and its radius to position the other smaller circles relative to that also, inside the circumference.

Drawing an image using sub-pixel level accuracy using Graphics2D

I am currently attempting to draw images on the screen at a regular rate like in a video game.
Unfortunately, because of the rate at which the image is moving, some frames are identical because the image has not yet moved a full pixel.
Is there a way to provide float values to Graphics2D for on-screen position to draw the image, rather than int values?
Initially here is what I had done:
BufferedImage srcImage = sprite.getImage ( );
Position imagePosition = ... ; //Defined elsewhere
g.drawImage ( srcImage, (int) imagePosition.getX(), (int) imagePosition.getY() );
This of course thresholds, so the picture doesn't move between pixels, but skips from one to the next.
The next method was to set the paint color to a texture instead and draw at a specified position. Unfortunately, this produced incorrect results that showed tiling rather than correct antialiasing.
g.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
BufferedImage srcImage = sprite.getImage ( );
g.setPaint ( new TexturePaint ( srcImage, new Rectangle2D.Float ( 0, 0, srcImage.getWidth ( ), srcImage.getHeight ( ) ) ) );
AffineTransform xform = new AffineTransform ( );
xform.setToIdentity ( );
xform.translate ( onScreenPos.getX ( ), onScreenPos.getY ( ) );
g.transform ( xform );
g.fillRect(0, 0, srcImage.getWidth(), srcImage.getHeight());
What should I do to achieve the desired effect of subpixel rendering of an Image in Java?
You can use a BufferedImage and AffineTransform, draw to the buffered image, then draw the buffered image to the component in the paint event.
/* overrides the paint method */
#Override
public void paint(Graphics g) {
/* clear scene buffer */
g2d.clearRect(0, 0, (int)width, (int)height);
/* draw ball image to the memory image with transformed x/y double values */
AffineTransform t = new AffineTransform();
t.translate(ball.x, ball.y); // x/y set here, ball.x/y = double, ie: 10.33
t.scale(1, 1); // scale = 1
g2d.drawImage(image, t, null);
// draw the scene (double percision image) to the ui component
g.drawImage(scene, 0, 0, this);
}
Check my full example here: http://pastebin.com/hSAkYWqM
You can composite the image yourself using sub-pixel accuracy, but it's more work on your part. Simple bilinear interpolation should work well enough for a game. Below is psuedo-C++ code for doing it.
Normally, to draw a sprite at location (a,b), you'd do something like this:
for (x = a; x < a + sprite.width; x++)
{
for (y = b; y < b + sprite.height; y++)
{
*dstPixel = alphaBlend (*dstPixel, *spritePixel);
dstPixel++;
spritePixel++;
}
dstPixel += destLineDiff; // Move to start of next destination line
spritePixel += spriteLineDiff; // Move to start of next sprite line
}
To do sub-pixel rendering, you do the same loop, but account for the sub-pixel offset like so:
float xOffset = a - floor (a);
float yOffset = b - floor (b);
for (x = floor(a), spriteX = 0; x < floor(a) + sprite.width + 1; x++, spriteX++)
{
for (y = floor(b), spriteY = 0; y < floor (b) + sprite.height + 1; y++, spriteY++)
{
spriteInterp = bilinearInterp (sprite, spriteX + xOffset, spriteY + yOffset);
*dstPixel = alphaBlend (*dstPixel, spriteInterp);
dstPixel++;
spritePixel++;
}
dstPixel += destLineDiff; // Move to start of next destination line
spritePixel += spriteLineDiff; // Move to start of next sprite line
}
The bilinearInterp() function would look something like this:
Pixel bilinearInterp (Sprite* sprite, float x, float y)
{
// Interpolate the upper row of pixels
Pixel* topPtr = sprite->dataPtr + ((floor (y) + 1) * sprite->rowBytes) + floor(x) * sizeof (Pixel);
Pixel* bottomPtr = sprite->dataPtr + (floor (y) * sprite->rowBytes) + floor (x) * sizeof (Pixel);
float xOffset = x - floor (x);
float yOffset = y - floor (y);
Pixel top = *topPtr + ((*(topPtr + 1) - *topPtr) * xOffset;
Pixel bottom = *bottomPtr + ((*(bottomPtr + 1) - *bottomPtr) * xOffset;
return bottom + (top - bottom) * yOffset;
}
This should use no additional memory, but will take additional time to render.
I successfully solved my problem after doing something like lawrencealan proposed.
Originally, I had the following code, where g is transformed to a 16:9 coordinate system before the method is called:
private void drawStar(Graphics2D g, Star s) {
double radius = s.getRadius();
double x = s.getX() - radius;
double y = s.getY() - radius;
double width = radius*2;
double height = radius*2;
try {
BufferedImage image = ImageIO.read(this.getClass().getResource("/images/star.png"));
g.drawImage(image, (int)x, (int)y, (int)width, (int)height, this);
} catch (IOException ex) {
Logger.getLogger(View.class.getName()).log(Level.SEVERE, null, ex);
}
}
However, as noted by the questioner Kaushik Shankar, turning the double positions into integers makes the image "jump" around, and turning the double dimensions into integers makes it scale "jumpy" (why the hell does g.drawImage not accept doubles?!). What I found working for me was the following:
private void drawStar(Graphics2D g, Star s) {
AffineTransform originalTransform = g.getTransform();
double radius = s.getRadius();
double x = s.getX() - radius;
double y = s.getY() - radius;
double width = radius*2;
double height = radius*2;
try {
BufferedImage image = ImageIO.read(this.getClass().getResource("/images/star.png"));
g.translate(x, y);
g.scale(width/image.getWidth(), height/image.getHeight());
g.drawImage(image, 0, 0, this);
} catch (IOException ex) {
Logger.getLogger(View.class.getName()).log(Level.SEVERE, null, ex);
}
g.setTransform(originalTransform);
}
Seems like a stupid way of doing it though.
Change the resolution of your image accordingly, there's no such thing as a bitmap with sub-pixel coordinates, so basically what you can do is create an in memory image larger than what you want rendered to the screen, but allows you "sub-pixel" accuracy.
When you draw to the larger image in memory, you copy and resample that into the smaller render visible to the end user.
For example: a 100x100 image and it's 50x50 resized / resampled counterpart:
See: http://en.wikipedia.org/wiki/Resampling_%28bitmap%29

Categories

Resources