How can I draw a circle that compounds your cursor movement? - java

I am trying to draw a circle with my cursor while I am moving it. I know the circle wont be perfect but that does not really matter I just need the circle to compound on top of my organic cursor movements. I originally tried to do this with java's awt robot class but that ended up being futile because anytime I moved my mouse massive lines would extend infinitely far from where I made that movement. Here are two sets of code I tried (keep in mind I am calling these from a nativeMousePress event so I am holding down the left click the whole time).
int radius = 100;
for (double i = 0; i < (2 * Math.PI) + Math.PI / 6; i = i + Math.PI / 6) {
PointerInfo pointerA = MouseInfo.getPointerInfo();
Point a = pointerA.getLocation();
int yStart = (int) a.getY();
int xStart = (int) a.getX();
robot.mouseMove((int) ((xStart) + (radius * Math.cos(i))), (int) ((yStart) + (radius * Math.sin(i))));
robot.delay(68);
}
Here is my another attempt I had. I also want to mention that I need the delay in between each stroke.
robot.mouseMove(getX() + 40, getY() + 20);
robot.delay(1000);
robot.mouseMove(getX() + 20, getY() + 40);
robot.delay(1000);
robot.mouseMove(getX() - 20, getY() + 40);
robot.delay(1000);
robot.mouseMove(getX() - 40, getY() + 20);
robot.delay(1000);
robot.mouseMove(getX() - 40, getY() - 20);
robot.delay(1000);
robot.mouseMove(getX() - 20, getY() - 40);
robot.delay(1000);
robot.mouseMove(getX() + 20, getY() - 40);
robot.delay(1000);
robot.mouseMove(getX() + 40, getY() - 20);
public int getX() {
PointerInfo pointerA = MouseInfo.getPointerInfo();
Point a = pointerA.getLocation();
return (int) a.getX();
}
public int getY() {
PointerInfo pointerA = MouseInfo.getPointerInfo();
Point a = pointerA.getLocation();
return (int) a.getY();
}
Ok now here is the image that shows what happens when I barely move my mouse. This happens with both sets of code even though each set of code makes the circle slightly different.
Now to reiterate what I am trying to do I want to be able to move my mouse freely around the canvas while the code tries to make circles which should likely lead to a compounding effect. The issue is when I tried to use the robot class it completely bugs out and makes massive lines every which way if you attempt to move the mouse. I already asked other people about this and no one could figure out a solution to this so I am wondering if there is another class I can access that can do what I am looking for. Anyways here is a picture of what I assume it would look like if I moved my cursor to the right and if my circle code worked. (I already figured out how to do the loop effect)
Lastly I wanted to mention that I dont want a solution that provides code that can make the shape I showed above because thats not the point since I plan to do more complex things with this later. I just really need to know how to automate moving my cursor while having its movements compound with my active mouse movements.

The java.awt.Robot generates inputs events automatically. In your code, for one human input event, robot is generating 12 input events over 68x12 milliseconds. So while robot is still generating 12 events if human gives more input events then mouse pointer location will jump back and forth between robot inputs and human inputs. The problem is both robots and human are giving mouse coordinates at the same time.
one solution could be to ignore human events while robot is generating click events. But distinguishing between robot generated events and human generated events will be very hard task. And things will get complicated.
I think the easiest option will be to draw one circle for one human mouse drag input. Think it as circle/spring pattern brush. Like they have air brush in drawing tools.
I know you don't want the code. But to convey my points better here is minimal code for the approach:
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Test extends Frame implements MouseMotionListener {
private int x1, y1, x2, y2;
private double i, radius = 10;
private Object lock = new Object();
public void init() throws Exception {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
dispose();
System.exit(0);
}
});
addMouseMotionListener(this);
setBounds(50, 50, 500, 550);
setVisible(true);
}
public static void main(String[] argv) throws Exception {
new Test().init();
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g.setColor(Color.black);
g.drawLine(x1, y1, x2, y2);
}
public void mouseDragged(MouseEvent me) {
me.consume();
//do this to avoid multiple circles drawing at the same time
synchronized (lock) {
int x = me.getX();
int y = me.getY();
if (x1 == 0) x1 = x;
if (y1 == 0) y1 = y;
i=Math.PI+(Math.PI/6)*2;
for (int j = 0; j < 13; j++, i +=(Math.PI / 6)) {
x2 = (int) (x + (radius * Math.cos(i)));
y2 = (int) (y + (radius * Math.sin(i)));
paint(getGraphics());
x1 = x2;
y1 = y2;
radius += 0.3;
}
try {
Thread.sleep(150); //change delay to suite ease of use
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void mouseMoved(MouseEvent me) { //reset
synchronized(lock) {
radius = 10;
x1 = 0;
y1 = 0;
}
}
}
And the output:

Related

How to create a new object(rectangle) everytime when the button is clicked?

I want to create a shape Object(in my case the object is a rectangle). Each time I click a button. Currently, I'm able to make it appear just once. The idea would be that each time I click the button, a new rectangle Object is created, additional to the old one. Therefore, if I click the button 5 times, I should have 5 rectangles.
I tried to do it with an ArrayList, but still, there is just one rectangle appearing. Does someone know how to do it!
Thank you very much in advance!
This is the main class, FYI there is also a rectangle Class(not attached)
import controlP5.*;
ControlP5 cp5;
Rectangle rect; // rect begins as null
Button rc;
ArrayList<Rectangle> rectList;
void setup(){
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
rc = cp5.addButton("Rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
rc.onRelease(new CallbackListener() {
public void controlEvent(CallbackEvent theEvent) {
// only create the rectangle when the button is clicked
rect = new Rectangle(100, 100, 100, 100);
}
});
}
void draw(){
background(255);
// if the rect exists, draw it on the screen
if(rect != null) {
rect.displayRect();
showRect();
}
for(int i = 0; i < rectList.size(); i++){
//((Rectangle)rectList.get(i)).update();
((Rectangle)rectList.get(i)).displayRect();
}
}
public void showRect(){
for(Rectangle r: rectList){
r.displayRect();
rect(r.getXvalue(), r.getYvalue(), r.getWvalue(), r.getHvalue());
}
}
You have a list, but you never add anything to that list. The list remains empty.
Drop the member field rect, delete this line:
Rectangle rect; // rect begins as null
When you instantiate a new Rectangle, immediately add it to the list.
rc.onRelease( new CallbackListener() {
public void controlEvent(CallbackEvent theEvent) {
// When the button is clicked, instantiate a new rectangle and remember it by adding to our list of rectangles.
rectList.add(
new Rectangle( 100, 100, 100, 100 )
);
}
});
Some chiding: This was not a good Question for Stack Overflow. You could easily have found this bug by using a debugger to step through the code. You would have seen that the list remains empty. Before posting, do your own debugging exhaustively.
You should post your Rectangle class to make it easier for others to test and help out.
As Basil pointed out (+1) you're only rendering a new rectangle for one frame when there's a click event.
The idea would be that each time I click the button, a new rectangle Object is created, additional to the old one. Therefore, if I click the button 5 times, I should have 5 rectangles.
This statement is a bit ambiguous. I get you'd like to render a rectangle per click, however in the click handler the rect has the exact same dimensions and coordinates. Even if you would make minor fixes, rendering 5 identical rectangles on top of each other will likely appear as if it's a single rectangle.
Regarding the code you posted, this stands out to me:
Rectangle rect; // rect begins as null: what is the purpose of the rect if you have this underneath: ArrayList<Rectangle> rectList; ?
showRect(); is called in draw(): it loops over rectList and not only calls displayRect() which I'd assume would render the current rect, but also re-renders the same data on the following line (rect(r.getXvalue(), r.getYvalue(), r.getWvalue(), r.getHvalue());)
underneath, there's a for loop over the same list calling displayRect() yet again. My guess is 2 out 3 calls to render rectangles are redundant. (Also the array list is typed therefore, no need to cast like this: (Rectangle)rectList.get(i)), rectList.get(i) should suffice)
The only other minor caveat I have is around naming: ideally you would want to stick to Java naming conventions in Processing. (For example getXValue() instead of getXvalue(), etc.)
Regarding the ControlP5 button you could use controlEvent() which is a bit simpler than setting a callback. Even simpler is to use this automatic variable plugging functionality. In short, if a function has the same name as a button's name it will be called automatically:
Automatic controller-event detection
ControlP5 offers a range of controllers that allow you to easily change and adjust values while your sketch is running. Each controller is identified by a unique name assigned when creating a controller. ControlP5 locates variables and functions inside your sketch and will link controllers to matching variables or functions automatically
(from controlP5 reference)
Here's a basic example that prints a message to console each time the button is clicked:
import controlP5.*;
ControlP5 cp5;
void setup() {
size(1000, 1000);
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw(){
background(255);
}
void rectangle(){
println("rectangle button clicked");
}
(I've kept the name rectangle instead of Rectangle to keep in line with Java naming conventions. The text label is displayed in uppercase anyway)
Back to your main question, if you want to add new rectangle per button press and render them the code be as simple as:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
int x = 100;
int y = 100;
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
}
void rectangle(){
rectList.add(new Rectangle(x, y, 100, 100));
// increment x, y to avoid superimposed rectangles
x += 50;
y += 50;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
// currently not used
public int getX(){
return x;
}
public int getY(){
return x;
}
public int getWidth(){
return x;
}
public int getHeight(){
return x;
}
}
Rectangle rect; stands out. If this was an OOP homework assignment or exercise perhaps the intention was to have a basic drawing app functionality where the user could have a rectangle drawing tool ?
If that's the case rect could be selection rectangle which could cloned into rectList so it persists.
You could implement rectangle selection like so:
when the mouse is pressed remember the coordinates: these are the starting point of the selection
as the mouse is dragged the end point coordinates are the current mouse coordinates, hence the selection rectangle dimensions are the difference between the current mouse coordinates and the previously stored mouse coordinates
as the mouse is released, reset the selection rectangle (so it no longer displays)
Here's a basic example sketch:
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup(){
size(1000, 1000);
}
void draw(){
background(255);
selection.display();
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
selection.w = selection.h = selection.x = selection.y = 0;
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
}
Resetting the Rectangle properties to 0 could be nicely encapsulated into a method:
void reset(){
x = y = w = h = 0;
}
The release handler would also be useful to add a new rectangle to rectList which has the same properties (x, y, w, h) as the selection, but before the selection is reset. something like:
void mouseReleased(){
// add a copy of the selection to rectList
rectList.add(new Rectangle(selection.x, selection.y, selection.w, selection.h));
// reset selection
selection.reset();
}
Again, the copy functionality is something that could be nicely encapsulated as a method as well:
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
Putting it all together would look like this:
import controlP5.*;
ControlP5 cp5;
ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
Rectangle selection = new Rectangle(0, 0, 0, 0);
void setup() {
size(1000, 1000);
rectList = new ArrayList<Rectangle>();
cp5 = new ControlP5(this);
cp5.addButton("rectangle").
setPosition(5, 4).
setColorBackground(color(52, 55, 76));
}
void draw() {
background(255);
// draw previous rectangles (black)
stroke(0);
for (int i = 0; i < rectList.size(); i++) {
rectList.get(i).display();
}
// draw current selection (green)
stroke(0, 192, 0);
selection.display();
}
void rectangle(){
println("selected drawing tool is rectangle");
}
void mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
void mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
void mouseReleased(){
// add a new rectangle to the list: a copy of the selection
rectList.add(selection.copy());
// reset selection
selection.reset();
}
class Rectangle{
private int x, y, w, h;
Rectangle(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
void display(){
rect(x, y, w, h);
}
Rectangle copy(){
return new Rectangle(x, y, w, h);
}
void reset(){
x = y = w = h = 0;
}
}
At this stage the button is a bit redundant, however it could useful in the future if other shapes are required (e.g. an Ellipse would be an obviously simple one to implement since ellipse() has the same parameters as rect(), just need to ensure ellipseMode(CORNER) is set to use the same selection x,y coordinates the rectangle does)
Hopefully this is useful. The initial code, as mentioned before looks a bit messy, as if it's put together in a haste before a deadline.
(I assume this because it reminds me of my code as a student :))
I'd recommend taking a short walk away from the computer, remembering what the task is and pen on paper breaking the task into small, clear, easy to implement subtasks. Once that is as clear as it can be, implement one subtask at a time in isolation. Initially the code may break or get messy, but eventually it will work (and it will be easier to write compared to the whole drawing program). Once that works, cleanup the code so that all unnecessary code is removed and it's easy to move the code to another sketch and run it without errors. Repeat the process for each subtask which should result in multiple minimal sketches solving one single problem. Once all parts are solved in isolation you can start putting the code together into one main sketch, however I recommend adding one subtask code as a time and testing first. When mixing code from multiple sketches conflicts/errors may arise and it will far easier to tackle merging two sketches a time than all of the subtask sketches in one go. Best of luck !

Java snap to grid

Okay so I'm trying to make things snap to a grid I have.
This is how I snap to the screen itself:
int finalCalcX = (mouseX / Handler.gridSpace32) * Handler.gridSpace32;
int finalCalcY = (mouseY / Handler.gridSpace32) * Handler.gridSpace32;
The variable names speak for themselves I think.
Mouse coordinates divided by my tiles being 32x32 pixels, times that again to get the snap-to-grid functionality.
Now this works fine for the screen, but when I want to add it to the "map" itself, I can't just add my map x and y offsets to that, it gets messed up.
I've played around with it for about two days, and I also got it to snap to the map itself, but when I'm say, halfway in the map on both axis, the mouseX and mouseY messes the grid thing up.
It's kind of hard for me to explain, but the offset from the 0, 0 (every origins position, even the screen) PLUS the maps offset when you move away from the origin, gets added to the distance between the cursor itself and the transparent snap-to-grid tile that I'm using to test.
Basically the offset between the maps origin, and the camera, is for some reason the same offset between the cursor and the transparent tile. So the further into the map i move, the further away the tile gets from the cursor, and eventually moves outside the screen width and height...
When I move further into the map, I want the snap-to-grid functionality to stay corret, no matter where on the map I am.
Render method:
for (int y = startY; y < endY; y++) {
for (int x = startX; x < endX; x++) {
gridSpace(graphics, (int) (x * Handler.gridSpace32 - handler.getCamera().getOffsetX()),
(int) (y * Handler.gridSpace32 - handler.getCamera().getOffsetY()));
checkHighlight(graphics);
}
}
The gridSpace is the grid itself.
Here is what's in the highlight at the moment:
int finalCalcX = (mouseX / Handler.gridSpace32) * Handler.gridSpace32;
int finalCalcY = (mouseY / Handler.gridSpace32) * Handler.gridSpace32;
graphics.setColor(new Color(100, 200, 100, 3));
graphics.fillRect(finalCalcX, finalCalcY, Handler.gridSpace32, Handler.gridSpace32);
Sorry for my terrible explanation skills, but that's the best I can do.
What am I doing wrong?
I think I recreated what you are getting, and the problem lies with usage of incorrect sign in calculations of camera position and translation. Executing code below you should get similar behavior to what you described, while uncommenting commented lines (while commenting out the ones that follow them) should give you correct behavior.
package test;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.*;
public class SnapToGrid extends JPanel implements MouseMotionListener{
private int[] camera;
private int[] mouse;
private final int gridSize = 16;
SnapToGrid() {
camera = new int[2];
mouse = new int[2];
setFocusable(true);
addMouseMotionListener(this);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
//g2.translate(-camera[0], -camera[1]);
g2.translate(camera[0], camera[1]);
//draw background
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++)
{
Color c = ((j*9) + i) % 2 == 0 ? Color.black : Color.white;
g2.setColor(c);
g2.fillRect(i*gridSize, j*gridSize, gridSize, gridSize);
}
g2.setColor(Color.blue);
int[] snappedPos = getSnappedMousePosition();
g2.fillRect(snappedPos[0], snappedPos[1], gridSize, gridSize);
}
private int[] getSnappedMousePosition() {
return new int[] {
camera[0] + mouse[0] - ((camera[0] + mouse[0]) % gridSize),
camera[1] + mouse[1] - ((camera[1] + mouse[1]) % gridSize)
};
}
public static void main (String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SnapToGrid());
frame.pack();
frame.setVisible(true);
}
#Override
public void mouseDragged(MouseEvent e) {
//camera[0] -= e.getX() - mouse[0];
//camera[1] -= e.getY() - mouse[1];
camera[0] += e.getX() - mouse[0];
camera[1] += e.getY() - mouse[1];
mouse[0] = e.getX();
mouse[1] = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
mouse[0] = e.getX();
mouse[1] = e.getY();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(gridSize * 18, gridSize * 18);
}
}
One thing that I really don't like with your code, is that you are not using transformations. Using transformations allows you to separate world from viewport, submits to far easier debugging of issues like this here, and most importantly, if you want to add things like scaling or rotating later on, you only need to add few lines, as opposed to rewriting half of your render method.

How can I detect the proximity between two images [duplicate]

I have two characters displayed in a game I am writing, the player and the enemy. defined as such:
public void player(Graphics g) {
g.drawImage(plimg, x, y, this);
}
public void enemy(Graphics g) {
g.drawImage(enemy, 200, 200, this);
}
Then called with:
player(g);
enemy(g);
I am able to move player() around with the keyboard, but I am at a loss when trying to detect a collision between the two. A lot of people have said to use Rectangles, but being a beginner I cannot see how I would link this into my existing code. Can anyone offer some advice for me?
I think your problem is that you are not using good OO design for your player and enemies. Create two classes:
public class Player
{
int X;
int Y;
int Width;
int Height;
// Getters and Setters
}
public class Enemy
{
int X;
int Y;
int Width;
int Height;
// Getters and Setters
}
Your Player should have X,Y,Width,and Height variables.
Your enemies should as well.
In your game loop, do something like this (C#):
foreach (Enemy e in EnemyCollection)
{
Rectangle r = new Rectangle(e.X,e.Y,e.Width,e.Height);
Rectangle p = new Rectangle(player.X,player.Y,player.Width,player.Height);
// Assuming there is an intersect method, otherwise just handcompare the values
if (r.Intersects(p))
{
// A Collision!
// we know which enemy (e), so we can call e.DoCollision();
e.DoCollision();
}
}
To speed things up, don't bother checking if the enemies coords are offscreen.
First, use the bounding boxes as described by Jonathan Holland to find if you may have a collision.
From the (multi-color) sprites, create black and white versions. You probably already have these if your sprites are transparent (i.e. there are places which are inside the bounding box but you can still see the background). These are "masks".
Use Image.getRGB() on the mask to get at the pixels. For each pixel which isn't transparent, set a bit in an integer array (playerArray and enemyArray below). The size of the array is height if width <= 32 pixels, (width+31)/32*height otherwise. The code below is for width <= 32.
If you have a collision of the bounding boxes, do this:
// Find the first line where the two sprites might overlap
int linePlayer, lineEnemy;
if (player.y <= enemy.y) {
linePlayer = enemy.y - player.y;
lineEnemy = 0;
} else {
linePlayer = 0;
lineEnemy = player.y - enemy.y;
}
int line = Math.max(linePlayer, lineEnemy);
// Get the shift between the two
x = player.x - enemy.x;
int maxLines = Math.max(player.height, enemy.height);
for ( line < maxLines; line ++) {
// if width > 32, then you need a second loop here
long playerMask = playerArray[linePlayer];
long enemyMask = enemyArray[lineEnemy];
// Reproduce the shift between the two sprites
if (x < 0) playerMask << (-x);
else enemyMask << x;
// If the two masks have common bits, binary AND will return != 0
if ((playerMask & enemyMask) != 0) {
// Contact!
}
}
Links: JGame, Framework for Small Java Games
You don't want to have the collision check code inside the painting code. The painting needs to be fast. Collision can go in the game loop. Therefore you need an internal representation of the objects independent of their sprites.
Here's the main class from my collision detection program.
You can see it run at: http://www.youtube.com/watch?v=JIXhCvXgjsQ
/**
*
* #author Tyler Griffin
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.GraphicsDevice.*;
import java.util.ArrayList;
import java.awt.Graphics;
import java.awt.geom.Line2D;
public class collision extends JFrame implements KeyListener, MouseMotionListener, MouseListener
{
ArrayList everything=new ArrayList<tile>();
int time=0, x, y, width, height, up=0, down=0, left=0, right=0, mouse1=0, mouse2=0;
int mouseX, mouseY;
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice screen = environment.getDefaultScreenDevice();
DisplayMode displayMode = screen.getDisplayMode();
//private BufferStrategy strategy;
JLayeredPane pane = new JLayeredPane();
tile Tile;
circle Circle;
rectangle Rectangle;
textPane text;
public collision()
{
setUndecorated(screen.isFullScreenSupported());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLayout(null);
setResizable(false);
screen.setFullScreenWindow(this);
width=displayMode.getWidth();
height=displayMode.getHeight();
Circle=new circle(-(int)Math.round((double)height/7*2),-(int)Math.round((double)height/7*2),(int)Math.round((double)height/7*.85),this);
Rectangle=new rectangle(-(int)Math.round((double)height/7*1.5),-(int)Math.round((double)height/7*1.5),(int)Math.round((double)height/7*1.5),(int)Math.round((double)height/7*1.5),this);
Tile=Circle;
Tile.move(mouseX-Tile.width/2, mouseY-Tile.height/2);
text=new textPane(0,0,width,height,this);
everything.add(new circle((int)Math.round((double)width/100*75),(int)Math.round((double)height/100*15),(int)Math.round((double)width/100*10),this));
everything.add(new rectangle((int)Math.round((double)width/100*70),(int)Math.round((double)height/100*60),(int)Math.round((double)width/100*20),(int)Math.round((double)height/100*20),this));
//everything.add(new line(750,250,750,750,this));
/*everything.add(new line(width/700*419,height/700*68,width/700*495,height/700*345,this));
everything.add(new line(width/700*495,height/700*345,width/700*749,height/700*350,this));
everything.add(new line(width/700*749,height/700*350,width/700*549,height/700*519,this));
everything.add(new line(width/700*549,height/700*519,width/700*624,height/700*800,this));
everything.add(new line(width/700*624,height/700*800,width/700*419,height/700*638,this));
everything.add(new line(width/700*419,height/700*638,width/700*203,height/700*800,this));
everything.add(new line(width/700*203,height/700*800,width/700*279,height/700*519,this));
everything.add(new line(width/700*279,height/700*519,width/700*76,height/700*350,this));
everything.add(new line(width/700*76,height/700*350,width/700*333,height/700*345,this));
everything.add(new line(width/700*333,height/700*345,width/700*419,height/700*68,this));
everything.add(new line(width/950*419,height/700*68,width/950*624,height/700*800,this));
everything.add(new line(width/950*419,height/700*68,width/950*203,height/700*800,this));
everything.add(new line(width/950*76,height/700*350,width/950*624,height/700*800,this));
everything.add(new line(width/950*203,height/700*800,width/950*749,height/700*350,this));
everything.add(new rectangle(width/950*76,height/700*350,width/950*673,1,this));*/
everything.add(new line((int)Math.round((double)width/1350*419),(int)Math.round((double)height/1000*68),(int)Math.round((double)width/1350*624),(int)Math.round((double)height/1000*800),this));
everything.add(new line((int)Math.round((double)width/1350*419),(int)Math.round((double)height/1000*68),(int)Math.round((double)width/1350*203),(int)Math.round((double)height/1000*800),this));
everything.add(new line((int)Math.round((double)width/1350*76),(int)Math.round((double)height/1000*350),(int)Math.round((double)width/1350*624),(int)Math.round((double)height/1000*800),this));
everything.add(new line((int)Math.round((double)width/1350*203),(int)Math.round((double)height/1000*800),(int)Math.round((double)width/1350*749),(int)Math.round((double)height/1000*350),this));
everything.add(new rectangle((int)Math.round((double)width/1350*76),(int)Math.round((double)height/1000*350),(int)Math.round((double)width/1350*673),1,this));
addKeyListener(this);
addMouseMotionListener(this);
addMouseListener(this);
}
public void keyReleased(KeyEvent e)
{
Object source=e.getSource();
int released=e.getKeyCode();
if (released==KeyEvent.VK_A){left=0;}
if (released==KeyEvent.VK_W){up=0;}
if (released==KeyEvent.VK_D){right=0;}
if (released==KeyEvent.VK_S){down=0;}
}//end keyReleased
public void keyPressed(KeyEvent e)
{
Object source=e.getSource();
int pressed=e.getKeyCode();
if (pressed==KeyEvent.VK_A){left=1;}
if (pressed==KeyEvent.VK_W){up=1;}
if (pressed==KeyEvent.VK_D){right=1;}
if (pressed==KeyEvent.VK_S){down=1;}
if (pressed==KeyEvent.VK_PAUSE&&pressed==KeyEvent.VK_P)
{
//if (paused==0){paused=1;}
//else paused=0;
}
}//end keyPressed
public void keyTyped(KeyEvent e){}
//***********************************************************************************************
public void mouseDragged(MouseEvent e)
{
mouseX=(e.getX());
mouseY=(e.getY());
//run();
}
public void mouseMoved(MouseEvent e)
{
mouseX=(e.getX());
mouseY=(e.getY());
//run();
}
//***********************************************************************************************
public void mousePressed(MouseEvent e)
{
if(e.getX()==0 && e.getY()==0){System.exit(0);}
mouseX=(e.getX()+x);
mouseY=(e.getY()+y);
if(Tile instanceof circle)
{
Circle.move(0-Circle.width, 0-Circle.height);
Circle.setBounds(Circle.x, Circle.y, Circle.width, Circle.height);
Tile=Rectangle;
}
else
{
Rectangle.move(0-Rectangle.width, 0-Rectangle.height);
Rectangle.setBounds(Rectangle.x, Rectangle.y, Rectangle.width, Rectangle.height);
Tile=Circle;
}
Tile.move(mouseX-Tile.width/2, mouseY-Tile.height/2);
}
public void mouseReleased(MouseEvent e)
{
//run();
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
//***********************************************************************************************
public void run()//run collision detection
{
while (this == this)
{
Tile.move(Tile.x + ((mouseX - (Tile.x + (Tile.width / 2))) / 10), Tile.y + ((mouseY - (Tile.y + (Tile.height / 2))) / 10));
//Tile.move((mouseX - Tile.width / 2), mouseY - (Tile.height / 2));
for (int i = 0; i < everything.size(); i++)
{
tile Temp = (tile) everything.get(i);
if (Temp.x < (Tile.x + Tile.width) && (Temp.x + Temp.width) > Tile.x && Temp.y < (Tile.y + Tile.height) && (Temp.y + Temp.height) > Tile.y)//rectangles collided
{
if (Temp instanceof rectangle)
{
if (Tile instanceof rectangle){rectangleRectangle(Temp);}
else {circleRectangle(Temp);}//Tile instanceof circle
}
else
{
if (Temp instanceof circle)
{
if (Tile instanceof rectangle) {rectangleCircle(Temp);}
else {circleCircle(Temp);}
}
else//line
{
if (Tile instanceof rectangle){rectangleLine(Temp);}
else{circleLine(Temp);}
}
}
}//end if
}//end for
try {Thread.sleep(16L);}
catch (Exception e) {}
Tile.setBounds(Tile.x, Tile.y, Tile.width, Tile.height);
//Rectangle.setBounds(x, y, width, height);
//Circle.setBounds(x, y, width, height);
repaint();
text.out=" ";
}//end while loop
}//end run
//***************************************special collision detection/handling functions************************************************
void rectangleRectangle(tile Temp)
{
int lapTop, lapBot, lapLeft, lapRight, small, scootX=0, scootY=0;
lapTop=(Temp.y+Temp.height)-Tile.y;
lapBot=(Tile.y+Tile.height)-Temp.y;
lapLeft=(Temp.x+Temp.width)-Tile.x;
lapRight=(Tile.x+Tile.width)-Temp.x;
small=999999999;
if (lapTop<small){small=lapTop; scootX=0; scootY=lapTop;}
if (lapBot<small){small=lapBot; scootX=0; scootY=lapBot*-1;}
if (lapLeft<small){small=lapLeft; scootX=lapLeft; scootY=0;}
if (lapRight<small){small=lapRight; scootX=lapRight*-1; scootY=0;}
Tile.move(Tile.x+scootX, Tile.y+scootY);text.out="collision detected!";
}
void circleRectangle(tile Temp)
{
if((Tile.x+Tile.width/2<=Temp.x+Temp.width && Tile.x+Tile.width/2>=Temp.x)||(Tile.y+Tile.height/2>=Temp.y && Tile.y+Tile.height/2<=Temp.y+Temp.height))
{
rectangleRectangle(Temp);
}
else//push from nearest corner
{
int x,y;
if(Tile.x+Tile.width/2>Temp.x+Temp.width && Tile.y+Tile.height/2<Temp.y){x=Temp.x+Temp.width; y=Temp.y;}
else if(Tile.x+Tile.width/2<Temp.x && Tile.y+Tile.height/2<Temp.y){x=Temp.x; y=Temp.y;}
else if(Tile.x+Tile.width/2>Temp.x+Temp.width && Tile.y+Tile.height/2>Temp.y+Temp.height){x=Temp.x+Temp.width; y=Temp.y+Temp.height;}
else {x=Temp.x; y=Temp.y+Temp.height;}
double distance = Math.sqrt(Math.pow(Tile.x+(Tile.width/2) - x, 2) + Math.pow(Tile.y+(Tile.height/2) - y, 2));
if((int)Math.round(distance)<Tile.height/2)
{
double normY = ((Tile.y+(Tile.height/2) - y) / distance);
double normX = ((Tile.x+(Tile.width/2) - x) / distance);
Tile.move(x-Tile.width/2+(int)Math.round(normX*((Tile.width/2))) , y-Tile.height/2+(int)Math.round(normY*((Tile.height/2))));text.out="collision detected!";
}
}
}
void rectangleCircle(tile Temp)
{
if((Temp.x+Temp.width/2<=Tile.x+Tile.width && Temp.x+Temp.width/2>=Tile.x)||(Temp.y+Temp.height/2>=Tile.y && Temp.y+Temp.height/2<=Tile.y+Tile.height))
{
rectangleRectangle(Temp);
}
else//push from nearest corner
{
int x,y;
if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2<Tile.y){x=Tile.x+Tile.width; y=Tile.y;}
else if(Temp.x+Temp.width/2<Tile.x && Temp.y+Temp.height/2<Tile.y){x=Tile.x; y=Tile.y;}
else if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2>Tile.y+Tile.height){x=Tile.x+Tile.width; y=Tile.y+Tile.height;}
else {x=Tile.x; y=Tile.y+Tile.height;}
double distance = Math.sqrt(Math.pow(Temp.x+(Temp.width/2) - x, 2) + Math.pow(Temp.y+(Temp.height/2) - y, 2));
if((int)Math.round(distance)<Temp.height/2)
{
double normY = ((Temp.y+(Temp.height/2) - y) / distance);
double normX = ((Temp.x+(Temp.width/2) - x) / distance);
if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2<Tile.y){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2)))-Tile.width,(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2))));text.out="collision detected!";}
else if(Temp.x+Temp.width/2<Tile.x && Temp.y+Temp.height/2<Tile.y){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2))),(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2))));text.out="collision detected!";}
else if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2>Tile.y+Tile.height){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2)))-Tile.width,(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2)))-Tile.height);text.out="collision detected!";}
else {Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2))),(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2)))-Tile.height);text.out="collision detected!";}
}
}
}
void circleCircle(tile Temp)
{
double distance = Math.sqrt(Math.pow((Tile.x+(Tile.width/2)) - (Temp.x+(Temp.width/2)),2) + Math.pow((Tile.y+(Tile.height/2)) - (Temp.y+(Temp.height/2)), 2));
if((int)distance<(Tile.width/2+Temp.width/2))
{
double normX = ((Tile.x+(Tile.width/2)) - (Temp.x+(Temp.width/2))) / distance;
double normY = ((Tile.y+(Tile.height/2)) - (Temp.y+(Temp.height/2))) / distance;
Tile.move((Temp.x+(Temp.width/2))+(int)Math.round(normX*(Tile.width/2+Temp.width/2))-(Tile.width/2) , (Temp.y+(Temp.height/2))+(int)Math.round(normY*(Tile.height/2+Temp.height/2))-(Tile.height/2));text.out="collision detected!";
}
}
void circleLine(tile Temp)
{
line Line=(line)Temp;
if (Line.x1 < (Tile.x + Tile.width) && (Line.x1) > Tile.x && Line.y1 < (Tile.y + Tile.height) && Line.y1 > Tile.y)//circle may be hitting one of the end points
{
rectangle rec=new rectangle(Line.x1, Line.y1, 1, 1, this);
circleRectangle(rec);
remove(rec);
}
if (Line.x2 < (Tile.x + Tile.width) && (Line.x2) > Tile.x && Line.y2 < (Tile.y + Tile.height) && Line.y2 > Tile.y)//circle may be hitting one of the end points
{
rectangle rec=new rectangle(Line.x2, Line.y2, 1, 1, this);
circleRectangle(rec);
remove(rec);
}
int x1=0, y1=0, x2=Tile.x+(Tile.width/2), y2=Tile.y+(Tile.height/2);
x1=Tile.x+(Tile.width/2)-Line.height;//(int)Math.round(Line.xNorm*1000);
x2=Tile.x+(Tile.width/2)+Line.height;
if(Line.posSlope)
{
y1=Tile.y+(Tile.height/2)-Line.width;
y2=Tile.y+(Tile.height/2)+Line.width;
}
else
{
y1=Tile.y+(Tile.height/2)+Line.width;
y2=Tile.y+(Tile.height/2)-Line.width;
}
Point point=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
if (point.x < (Line.x + Line.width) && point.x > Line.x && point.y < (Line.y + Line.height) && point.y > Line.y)//line intersects within line segment
{
//if(point!=null){System.out.println(point.x+","+point.y);}
double distance = Math.sqrt(Math.pow((Tile.x+(Tile.width/2)) - point.x,2) + Math.pow((Tile.y+(Tile.width/2)) - point.y, 2));
if((int)distance<Tile.width/2)
{
//System.out.println("hit");
double normX = ((Tile.x+(Tile.width/2)) - point.x) / distance;
double normY = ((Tile.y+(Tile.height/2)) - point.y) / distance;
Tile.move((point.x)+(int)Math.round(normX*(Tile.width/2))-(Tile.width/2) , (point.y)+(int)Math.round(normY*(Tile.height/2))-(Tile.height/2));text.out="collision detected!";
//System.out.println(point.x+","+point.y);
}
}
//new bullet(this, (int)Math.round(tryX), (int)Math.round(tryY));
}
void rectangleLine(tile Temp)
{
line Line=(line)Temp;
if(new Line2D.Double(Line.x1,Line.y1,Line.x2,Line.y2).intersects(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height)))
{
if (Line.x1 < (Tile.x + Tile.width) && (Line.x1) > Tile.x && Line.y1 < (Tile.y + Tile.height) && Line.y1 > Tile.y)//circle may be hitting one of the end points
{
rectangle rec=new rectangle(Line.x1, Line.y1, 1, 1, this);
rectangleRectangle(rec);
remove(rec);
}
if (Line.x2 < (Tile.x + Tile.width) && (Line.x2) > Tile.x && Line.y2 < (Tile.y + Tile.height) && Line.y2 > Tile.y)//circle may be hitting one of the end points
{
rectangle rec=new rectangle(Line.x2, Line.y2, 1, 1, this);
rectangleRectangle(rec);
remove(rec);
}
if(Line.posSlope)//positive sloped line
{
//first we'll do the top left corner
int x1=Tile.x-Line.height;
int x2=Tile.x+Line.height;
int y1=Tile.y-Line.width;
int y2=Tile.y+Line.width;
Point topPoint=new Point(-99,-99), botPoint=new Point(-99,-99);
double topDistance=0, botDistance=0;
topPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
topDistance = Math.sqrt(Math.pow(Tile.x - topPoint.x,2) + Math.pow(Tile.y - topPoint.y, 2));
//new let's do the bottom right corner
x1=Tile.x+Tile.width-Line.height;
x2=Tile.x+Tile.width+Line.height;
y1=Tile.y+Tile.height-Line.width;
y2=Tile.y+Tile.height+Line.width;
botPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
botDistance = Math.sqrt(Math.pow((Tile.x+Tile.width) - botPoint.x,2) + Math.pow((Tile.y+Tile.height) - botPoint.y, 2));
if(topDistance<botDistance)
{
if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(topPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(topPoint))
{
Tile.move(topPoint.x,topPoint.y);text.out="collision detected!";
}
}
else
{
if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(botPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(botPoint))
{
Tile.move(botPoint.x-Tile.width,botPoint.y-Tile.height);text.out="collision detected!";
}
}
}
else//negative sloped lne
{
//first we'll do the top right corner
int x1=Tile.x+Tile.width-Line.height;
int x2=Tile.x+Tile.width+Line.height;
int y1=Tile.y+Line.width;
int y2=Tile.y-Line.width;
Point topPoint=new Point(-99,-99), botPoint=new Point(-99,-99);
double topDistance=0, botDistance=0;
topPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
topDistance = Math.sqrt(Math.pow(Tile.x + Tile.width - topPoint.x,2) + Math.pow(Tile.y - topPoint.y, 2));
//new let's do the bottom left corner
x1=Tile.x-Line.height;
x2=Tile.x+Line.height;
y1=Tile.y+Tile.height+Line.width;
y2=Tile.y+Tile.height-Line.width;
botPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
botDistance = Math.sqrt(Math.pow(Tile.x - botPoint.x,2) + Math.pow((Tile.y+Tile.height) - botPoint.y, 2));
if(topDistance<botDistance)
{
if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(topPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(topPoint))
{
Tile.move(topPoint.x-Tile.width,topPoint.y);text.out="collision detected!";
}
}
else
{
if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(botPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(botPoint))
{
Tile.move(botPoint.x,botPoint.y-Tile.height);text.out="collision detected!";
}
}
}
}
}
public Point intersection(double x1, double y1, double x2, double y2,double x3, double y3, double x4, double y4)//I didn't write this. got it from http://www.ahristov.com/tutorial/geometry-games/intersection-lines.html (I altered it)
{
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
int x=(int)Math.round(xi);
int y=(int)Math.round(yi);
return new Point(x, y);
}
//***************************************************************************************
public static void main(String[] args)
{
final collision Collision=new collision();
Collision.run();
}//end main
}//end class
Since Java doesn't have an intersect function (really!?) you can do collision detection by simply comparying the X and Y, Width and Height values of the bounding boxes (rectangle) for each of the objects that could potentially collide.
So... in the base object of each colliding object... i.e. if your player and enemy have a common base you can put a simple Rectangle object called something like BoundingBox. If the common base is a built in Java class then you'll need to create a class that extends the build in class and have the player and enemy objects extend your new class or are instances of that class.
At creation (and each tick or update) you'll need to set the BoundingBox paremeters for both your player and enemy. I don't have the Rectangle class infront of me but its most likely something like X, Y, Width and finally Height. X and Y are that objects location in your game world. The width and height are self explanatory I think. They'll most likely come out from the right of the players location though so, if the X and Y were bothe at 0 and your Width and Height were both at 256 you wouldn't see anything because the character would be at the top left outside of the screen.
Anyways... to detect a collision, you'll want to compare the attributes of the player and enemy BoundingBoxes. So something like this...
if( Player.BoundingBox.X = Enemy.BoundingBox.X && If( Player.BoundingBox.Y = Enemy.BoundingBox.Y )
{
//Oh noes! The enemy and player are on top of eachother.
}
The logic can get sort of complicated but you'll need to compare the distances between each BoundingBox and compare locations.
Here's a useful of an open source game that uses a lot of collisions: http://robocode.sourceforge.net/
You may take a look at the code and complement with the answers written here.
is there a problem with:
Rectangle box1 = new Rectangle(100,100,100,100);
Rectangle box2 = new Rectangle(200,200,100,100);
// what this means is if any pixel in box2 enters (hits) box1
if (box1.contains(box2))
{
// collision occurred
}
// your code for moving the boxes
this can also be applied to circles:
Ellipse2D.Double ball1 = new Ellipse2D.Double(100,100,200,200);
Ellipse2D.Double ball2 = new Ellipse2D.Double(400,100,200,200);
// what this means is if any pixel on the circumference in ball2 touches (hits)
// ball1
if (ball1.contains(ball2))
{
// collision occurred
}
// your code for moving the balls
to check whether youve hit the edge of a screen you could use the following:
Rectangle screenBounds = jpanel.getBounds();
Ellipse2D.Double ball = new Ellipse2D.Double(100,100,200,200); // diameter 200
Rectangle ballBounds = ball.getBounds();
if (!screenBounds.contains(ballBounds))
{
// the ball touched the edge of the screen
}
Use a rectangle to surround each player and enemy, the height and width of the rectangles should correspond to the object you're surrounding, imagine it being in a box only big enough to fit it.
Now, you move these rectangles the same as you do the objects, so they have a 'bounding box'
I'm not sure if Java has this, but it might have a method on the rectangle object called .intersects() so you'd do if(rectangle1.intersectS(rectangle2) to check to see if an object has collided with another.
Otherwise you can get the x and y co-ordinates of the boxes and using the height/width of them detect whether they've intersected yourself.
Anyway, you can use that to either do an event on intersection (make one explode, or whatever) or prevent the movement from being drawn. (revert to previous co-ordinates)
edit: here we go
boolean
intersects(Rectangle r)
Determines whether or not this Rectangle and the specified
Rectangle intersect.
So I would do (and don't paste this code, it most likely won't work, not done java for a long time and I didn't do graphics when I did use it.)
Rectangle rect1 = new Rectangle(player.x, player.y, player.width, player.height);
Rectangle rect2 = new Rectangle(enemy.x, enemy.y, enemy.width, enemy.height);
//detects when the two rectangles hit
if(rect1.intersects(rect2))
{
System.out.println("game over, g");
}
obviously you'd need to fit that in somewhere.
No need to use rectangles ... compare the coordinates of 2 players constantly.
like
if(x1===x&&y1==y)
remember to increase the range of x when ur comparing.
if ur rectangle width is 30 take as if (x1>x&&x2>x+30)..likewise y
It's Java code for collision of two or more ImageViews not rectangles or other,use ImageViews Instead.
1.This code of Collision works every where in any views or layouts.
2.Add a timer to repeat it and to detect collision repeatedly.
3.It only works with views and layout.
if ((getLocationX(_v1) > (getLocationX(_v2) - ((_w2*3) + 40))) && (getLocationX(_v1) < (getLocationX(_v2) + ((_w2*3) +40)))){
if ((getLocationY(_v1) > (getLocationY(_v2) - ((_h2*3) + 40))) && (getLocationY(_v1) < (getLocationY(_v2) + ((_h2*3) +40)))){
showMessage("Collided");
}
}

The paddle of pong keeps shaking without staying at one position

Please look at the following structure of my pong game.
gameLoop(); method
//Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while (running)
{
double now = System.nanoTime();
int updateCount = 0;
if (!paused)
{
//Do as many game updates as we need to, potentially playing catchup.
while( now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER )
{
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if ( now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
//float interpolation = 1.0f;
drawGame(interpolation);
lastRenderTime = now;
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while ( now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES)
{
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
try {Thread.sleep(1);} catch(Exception e) {}
now = System.nanoTime();
}
}
}
}
updateGame(); method
if(p1_up){
if(player.equals("p1")){
p1.moveUp();
}
else
{
p2.moveUp();
}
}
else if(p1_down){
if(player.equals("p1")){
p1.moveDown();
}
else
{
p2.moveDown();
}
}
moveUp(); moveDown(); method of paddle
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
drawGame(interpolation); method
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<balls.size();i++){
paintBall(g, balls.get(i));
}
drawPaddle(g, p1);
drawPaddle(g, p2);
}
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)((p.x - p.last_x)*interpolation + p.last_x);
paddle_drawY = (int)((p.y - p.last_y)*interpolation + p.last_y);
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
I am a beginner in game programming so i don't have a good idea about game loops. I found the above fixed time-step game loop in the internet and used it as the game loop for my game. The loop makes the ball move smoothly but the paddle isn't staying at one place when moved. When I move my paddle by pressing one down key stroke then the paddle keeps shaking
without stopping in one spot. The y coordinates of the paddle keeps changing like
33, 45, 20, 59, 34, 59, 34, 59, 33, 59, 34, 58
I know the problem is in interpolation value as it keeps changing value that will change the y coordinate of paddle in render. I have been thinking about this for a while and i don't know how to make the game loop work for any movements so i have come here for some help. I appreciate any suggestion/help!
Here is my full Paddle class.
public class Paddle
{
float x;
float y;
float last_y;
float last_x;
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
this.last_x = x;
this.last_y = y;
}
public void setNewX(int d){
last_y = y;
last_x = x;
x = d;
}
public void setNewY(int d){
last_y = y;
last_x = x;
y = d;
}
public void moveUp(){
last_y = y;
last_x = x;
y -= 50.0;
}
public void moveDown(){
last_y = y;
last_x = x;
y += 50.0;
}
}
and i initiate the paddle position in the main class through global variable.
public Paddle p1 = new Paddle(10, 10);
public Paddle p2 = new Paddle(950, 10);
I have following event listeners for handling key strokes.
Action handle_up_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = true;
}
};
Action handle_up_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_up = false;
}
};
Action handle_down_action = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = true;
}
};
Action handle_down_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
p1_down = false;
}
};
What are you trying to achieve with interpolation? From my understanding, it represents the percentage of time elapsed between previous previous and next "update time".
So it should progress continuously from 0 to 1 each 33.3 ms.
I don't know how you use this interpolation variable in the paintBall method, but for the paddles, it will draw your paddle at a "pseudo random position" between p.x;p.y and p.last_x;p.last_y (depending on the time between the two updateGame()).
In order to correct this, from your loop logic, you should understand that every game entity (balls, paddles, ...) must have two states (the positions):
- the logical state, which is updated only each TIME_BETWEEN_UPDATES
- the visual state, which can be updated anytime, at each render.
It is the same as if you have a set of points (which represent the logical states) and you want to interpolate anywhere between this points (reprensenting the visual state).
Your code is like this.
First solution
The simplest way to correct the paddle shaking, is to avoid the interpolation and use:
public void drawPaddle(Graphics g, Paddle p){
paddle_drawX = (int)p.x;
paddle_drawY = (int)p.y;
g.drawRect(paddle_drawX, paddle_drawY, 10, 50);
}
But your movement will look like this (visual position will be changed only each TIME_BETWEEN_UPDATES)
Second solution
You want p.x;p.y to be the logical position, but the visual position should be interpolated between p.last_x;p.last_y and the logical position if the rendering is done between the input processing and the next updateGame(): you must reset p.last_x;p.last_y when updateGame() is called. To achieve this, call the paddles' updateMovement() method inside updateGame().
public void updateMovement(){
last_y = y;
last_x = x;
}
You can have other solutions, such as to use a speed variable or a movement function, in order to have a smooth movement, accelerations, and so on. It is mainly a generalisation of second solution. It requires bigger changes, but it is more flexible and powerful. To achieve this, you may want to store in paddles the last "update position", and all movement-related variables, such as movement start date. Add a method to retrieve the "visual position" that can be called with any date between two updates, and a method to update the "logical position" called each updateGame().

Freehand painting in Java

I've been writing this little painting program thing, but whenever I release the mouse and move to another point on the screen, the line is drawn over there. I tried clearing the points when the mouse has been released, but that deletes everything on screen.
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
public class PaintingCanvas extends Canvas implements MouseMotionListener, MouseListener {
private ArrayList<Point> points = new ArrayList<Point>();
public PaintingCanvas(int width, int height) {
setBounds(0, 0, width, height);
addMouseMotionListener(this);
addMouseListener(this);
}
public void paint(Graphics g) {
for (int i = 0; i < points.size() - 2; i++) {
Point p1 = points.get(i);
Point p2 = points.get(i + 1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
#Override
public void mouseDragged(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
}
I suggest:
Call the super.paint(g); method first thing in your paint method.
When the mouse is released, paint the image represented by the points ArrayList to a BufferedImage and then clear the points ArrayList, and then call repaint().
Draw the BufferedImage in the paint method. before drawing your lines (but check that it's not null first). You do this with the Graphics#drawImage(Image image, int x, int y, ...) method.
Better, re-write this to work in Swing by painting in a JPanel's paintComponent method.
Of course this is happening - once you start drawing again, the new points are added after the old ones. Once you paint after that, they are included. You'll need to seperate the different paths from each other.
Have you looked at the Path classes? If you are simply drawing discrete lines to a screen, the GeneralPath class might be a simple solution.
The Drawing Arbitrary Shapes tutorial explains how to use these.
Basically, every time the user pressed the mouse (on a mousePressed event), you would call the path's moveTo(x, y) method. For every segment (replacing what you currently do in the mouseDragged() method), you would call the path's lineTo(x, y) method.
No matter what, you -definitely- need to handle mousePressed or mouseReleased events, or both, as you are looking for some way to indicate the start of a new line/path, rather than using the old one.
private void jPanel1MouseDragged(java.awt.event.MouseEvent evt) {
points.add(evt.getPoint());
for (int i = 0; i < points.size() - 2; i++)
{
Point p1 = points.get(i);
Point p2 = points.get(i + 1);
jPanel1.getGraphics().drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
private void jPanel1MousePressed(java.awt.event.MouseEvent evt) {
points.clear();
points.add(evt.getPoint());
}
I would make a 2d arraylist in which the first array is points added to until you lift up your finger then a new array is added for the second line etc...
Insert a garbage point -1,-1 in points inside mouseReleased method and check for it inside paint method and skip that point. Updated code:
#Override
public void mouseReleased(MouseEvent e) {
points.add(new Point(-1, -1));
}
#Override
public void paint(Graphics g) {
for (int i = 0; i < points.size() - 1; i++) {
Point p = points.get(i+1);
int x2 = p.x;
int y2 = p.y;
if ( x2 == -1 || y2 == -1) {
++i;
//continue // Considered bad practice, can play havoc with your system. (source http://xkcd.com/292/ ).
}
else {
p = points.get(i);
int x1 = p.x;
int y1 = p.y;
g.drawLine(x1, y1, x2, y2);
}
}
}
OP, how it feels to see this question after 3 years? :D

Categories