I'm currently trying to make something like a trail that follows an object. Well, basically I just create a "trail object" every second at X,Y of the main object. However, I can't make it work.
This the movement code for the main object.
dx = ((Math.sin(speed)*20);
speed = speed + 0.09;
x = x + dx;
My idea was that for making a trail I just need to subtract dx from x, so it would look like that
tick = tick + gameTimer.getDelay();
for(int i = 0; i < 100; i++)
{
if (tick > 1000*i)
{
g2d.drawOval(x-dx, y, 50, 50);
}
}
but apparently my theory is wrong and therefore I ask for your help people.
P.S. There is no code for "y" because I don't need it yet.
P.S.S I know that I'm missing a lot of details, so if you need some more info let me know and I'll paste some more code
Related
I am trying to set a location of geometric figure that appears in JFrame window. For example if it's a rectangle so i need to move it's left upper point 10 pixels right, and left lower point 10 pixels down.
I was trying to do like this but it didn't work:
public void relocate(ArrayList<MyShape> newShape){
int x1, x2, y1 , y2;
for(int i = 0; i < newShape.size(); i++){
x1 = (int)newShape.get(i).p1.getX();
y1 = (int)newShape.get(i).p1.getY();
x2 = (int)newShape.get(i).p2.getX();
y2 = (int)newShape.get(i).p2.getY();
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
if(newShape.get(i).getCol() != null){
newShape.get(i).setCol(Color.BLUE);
}
}
repaint();
}
Your code should work - in a sense that it changes the location of the objects on the screen. So, what's going on here? What's wrong with your solution?
I can give you a few hints though:
You can check if any other part of the code is messing with the location setting. It's possible that they override your settings.
Maybe this code runs outside of the AWT Thread. You can check it with SwingUtilities.isEventDispatchThread().
You can reuse the Point-s in Swing. Points are mutable object. This leads to not so clean code, but performance is important in this case:
MyShape shape = newShape.get(i);
Point p = shape.getP1();
p.setLocation(p.x, p.y + 10);
Maybe a revalidate() call can help too:
public void relocate(ArrayList<MyShape> newShape) {
// some code changing locations
revalidate(); // this is it
repatint();
}
The following analysis is based on assumptions about how MyShape works since you've declined to provide those details when asked for them.
Look at your algorithm. For each shape:
1) You're capturing the original values of P1 and P2. So far so good.
2) You're calling the shape's setLocation() method with an adjusted value for P1. Now, what does setLocation() do? Understanding that is part of why you were asked about the MyShape class, and saying it's a superclass for all shapes doesn't help.
3) You tell the shape to set its P1 to whatever value you get by querying its P1. If the getters and setters do anything reasonable, this won't do anything.
4) You then call setLocation() again, this time with an adjusted value for P2. Again, what does this do? It probably undoes whatever you accomplished in step 2.
5) You tell the shape to set its P2 to whatever value you get by querying its P2. Again, this probably doesn't do anything.
What you want to do, I assume, is set P1 based on the adjusted values you calculated in step 2; and set P2 based on the adjusted values in step 4. But that's not what your code says unless secLocation, getP1, and getP2 are all doing very ununtuitive things.
Not sure what MyShape does, but it seems that newShape.get(i).setP1 just overrides newShape.get(i).setLocation right before it. Try adjusting your code like this:
//Change this
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
//To this
newShape.get(i).getP1().setLocation(x1 + 10, y1);
newShape.get(i).getP2().setLocation(x2, y2 + 10);
I hope this helps.
I am using slick for java since a few days and got a serious problem.
If i run a completely empty apllication (it just shows the fps) with a solution of 800x600 i get a fps count between 700 and 800.
If I now draw an array with 13300 entries as a grid of green and white rectangles, the fps drop to something around 70.
With more entries in the array it becomes really slow.
For example in a solution of 1024x768 and an array with 21760 entries the fps drop to 40.
How i draw a single entry:
public void draw(Graphics graphics){
graphics.setColor(new Color(getColor().getRed(), getColor().getGreen(), getColor().getBlue(), getColor().getAlpha()));
graphics.fillRect(getPosition().x, getPosition().y, getSize().x, getSize().y);
Color_ARGB white = new Color_ARGB(Color_ARGB.ColorNames.WHITE);
graphics.setColor(new Color(white.getRed(), white.getGreen(), white.getBlue(), white.getAlpha()));
}
And this is how I draw the complete array:
public void draw(Graphics graphics) {
for (int ix = 0; ix < getWidth(); ix++) {
for (int iy = 0; iy < getHeight(); iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
In my opinion 21760 is not that much.
Is there anything wrong with my code or is slick just too slow to draw so much rectangles?
You only want to draw rectangles that are on the screen. If your screen bounds go from 0 to 1024 in the x direction and from 0 to 768 in the y direction, then you only want to loop through rectangles that are inside those bounds and then only draw those rectangles. I can't imagine you are trying to draw 21760 rectangles inside those bounds.
If you are, then try creating one static rectangle and then just try drawing that ONE in all of the different positions you need to draw it at rather than creating a new one every time. For example, in a game I am making, I might have 1000 tiles that are "grass" tiles, but all 1000 of those share the same static texture. So I only need to reference one image rather than each tile creating its own.
Each rectangle can still have a unique state. Just make your own rectangle class and have a static final Image that holds a 5*5 image. Each rectangle will use this image when it needs to be drawn. You can still have unique properties for each rectangle. For example, private Vector2f position, private boolean isAlive, etc
You're probably not going to be able to draw individual rectangles any faster than that.
Games that render millions of polygons per second do so using vertex buffer objects (VBO). For that, you'll probably need to code against the OpenGL API (LWJGL) itself, not a wrapper.
Not sure if Slick will allow it, but if this thing looks anything like a chessboard grid... you could draw just 4 rectangles, grab them and use the resulting image as a texture for your whole image. I'm not even a java programmer just trying to come up with a solution.
Since you're only repeatedly using just a few colors creating a new Color object for every single one is bound to be slow... use new only once for each different color used and store the re-usable colors somewhere in your class, than call the functions with those, constantly allocating and freeing memory is very slow.
And while this might not be as much a benefit as not using new each time but have you considered caching the results of all those function calls and rewriting code as
public void draw(Graphics graphics) {
int ixmax = getWidth();
int iymax = getHeight();
for (int ix = 0; ix < ixmax; ix++) {
for (int iy = 0; iy < iymax; iy++) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Or if you'd prefer not to declare new variables
public void draw(Graphics graphics) {
for (int ix = getWidth() - 1; ix >= 0; ix--) {
for (int iy = getHeight() - 1; iy >= 0; iy--) {
getGameGridAt(ix, iy).draw(graphics);
}
}
}
Just noticed in another answer you have an integral size grid (5x5) ... in this case the fastest way to go about this would seem to be to draw each item a single pixel (you can do this directly in memory using a 2-dimensional array) and scale it to 500% or use it as a texture and draw a single rectangle with it the final size you desire ... should be quite fast. Sorry for all the confusion caused by previous answers, you should have said what you're doing more clearly from the start.
If scaling and textures are not available you can still draw in memory using something like this (written in c++, please translate it to java yourself)
for( int x = 0; x < grid.width(); x++ ) {
for( int y = 0; y < grid.height(); y++ ) {
image[x*5][y*5] = grid.color[x][y];
image[x*5][y*5 + 1] = grid.color[x][y];
image[x*5][y*5 + 2] = grid.color[x][y];
image[x*5][y*5 + 3] = grid.color[x][y];
image[x*5][y*5 + 4] = grid.color[x][y];
}
memcpy(image[x*5+1], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+2], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+3], image[x*5], grid.height() * sizeof(image[0][0]) );
memcpy(image[x*5+4], image[x*5], grid.height() * sizeof(image[0][0]) );
}
I'm not sure, but perhaps for graphics the x and y might be represented in the reversed order than used here, so change the code accordingly if it that's the case (you'll figure that out as soon as a few iterations run), also your data is probably structured a bit differently but I think the idea should be clear.
I'm writing a simple game right now and I need to be able to detect collisions between many objects (checking if 10 objects collide with any 20 other objects but not between the two groups). I've written some simple code that works now but causes the game to slow down extremely after I detect the collision (in Java by the way):
//Check for collisions between tanks and bullets
ArrayList<Object> objectsToRemove = new ArrayList<Object>();
for (int i = 0; i < tanksOnScreen.size(); i += 1) {
//Get tank
Tank tank = tanksOnScreen.get(i);
for (int e = 0; e < bulletsOnScreen.size(); e += 1) {
//Get bullet
Bullet bullet = bulletsOnScreen.get(e);
//Check for collision
if (tank.collides(bullet.x, bullet.y, 10, 10)) {
System.out.println("Collide");
objectsToRemove.add(bullet);
objectsToRemove.add(tank);
break;
}
}
}
for (Object obj:objectsToRemove) {
if (obj.getClass().equals(Bullet.class)) {
bulletsOnScreen.remove(bulletsOnScreen.indexOf(obj));
} else if (obj.getClass().equals(Tank.class)) {
tanksOnScreen.remove(tanksOnScreen.indexOf(obj));
}
}
And the collides() method of the tank:
public boolean collides(float px, float py, float pwidth, float pheight) {
// If the distance between the two centers of the lines on x and y axis
// Is less than the distance of half the w and h added together, the objects
// Are colliding
float x1 = (px > x) ? x : px, x2 = (px > x) ? px : x, y1 = (py > y) ? y : py, y2 = (py > y) ? py : y;
float w1 = (x1 < x2) ? width : pwidth, w2 = (x1 < x2) ? pwidth : width, h1 = (y1 < y2) ? height : pheight, h2 = (y1 < y2) ? pheight : height;
if ((x2 + w2/2) - (x1 + w1/2) < (w1/2 + w2/2)&&(y2 + h2/2) - (y1 + h1/2) < (h1/2 + h2/2)) {
return true;
} else {
return false;
}
}
I assume the lag is because of the double for loops, to iterate over the objects. I'm not sure how to eradicate these for loops or how to get the bullets in a certain region of the screen and only check these bullet without using another for loop (segregation, I think). Can anyone point me in the right direction for collision detection with many objects? I don't mind what language the answer is in, even if it is pseudo code.
Thanks,
Ben
Edit 1
I'm right now using the Slick graphics API for java, which provides you with an update and render method to add rendering and game logic. I placed this collision detection in the update method (which is getting called every frame - about 60 times a second). The slowness occurs after the collision happens, and the objects are removed from the screen - which I find odd. Maybe a break command after deleting the objects in the for loop will eradicate it?
Edit 2
Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.
One good idea is to use octree. As the bullets will be moving I assume that you will need a kinetic version of it - there are a bunch of articles on kinetic data structures on the internet.
Also if you want to detect collisions between more complex convex polygons, I recommend you to use gjk algorithm which is very fast for such calculation. Note that this will speed up only the collision detection time for a pair of objects, the number of pairs will still remain the same.
Unless I'm missing something, or there's additional code you haven't shown, you're running in O(n^2), where n is 20. It should seem instantaneous to the user.
Try stepping through it in the debugger to see where it's slowing down.
Edit to elaborate: your expensive operation is not in the code you've posted. It's somewhere else, being called by the code you've posted.
Thanks for all the answers guys, and the references are a great help for the future. I fixed the problem only by swapping the bullet and tank for loops, so it didn't continue to loop after the bullet was destroyed. I shouldn't have asked the question, as it was quite easy to fix in the end. Dave and Banthar were right in saying that the problem wasn't with the code, and that it should be instantaneous.
What's the simplest way to draw a line between two Point objects in a way
that will look like I am drawing that line in real time by hand?
For example:
Point a = new Point(5,20);
Point b = new Point(15,20);
How do I connect these points with a "moving" line?
In other words I want to make the user feel "motion" of some sort. Is there a simple way to do that?
Given two points, you can determine the equation of the line connecting them. The equation of a line is of the form y = mx + c, where m is the slope, and c is the y intercept.
So, given your two points (5,20) and (15,20), we first determine m.
m = (y2-y1)/(x2-x1)
= (20-20)/(15-5)
= (0)/10
= 0
Substituting into the equation for a straight line, we get y = 0x + c or y = c. Now that we know this, we simply need to know the points where y = c and 5<=x<=15. Simply draw each of these points in the normal way (look at this for the exact method) with a Thread.sleep() call in between drawing each point. In this case, you have only 11 points to draw, so it would make sense to draw 1 point every 100 ms. For details on Thread.sleep() see here.
EDIT: Since Thread.sleep() won't work on the EDT, look at javax.swing.Timer instead, as Uhlen suggested.
Following the answer by Chinmay Kanchi, you need to create a feeling of animation. As mentioned above in comments by Uhlen you should use Swing's Timer when working on EDT. To give you example of how to use Timer. Lets assume we have a panel and we want it to slide open on e.g. a button click, thus we need to animate it sliding open by increasing its size. Below is an example showing pretty much how you would use Timer to do the operations.
this.extendingTimer = new Timer(0, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//assume sliding is vertical
int value = maximumHeight;
//make sure the size will not be bigger then allowed maximum
if(currentExtensionSize + extensionRate >= value)
{
currentExtensionSize = value;
stopExtending();
}
else
currentExtensionSize += extensionRate;
setSize(new Dimension(maximumWidth, currentExtensionSize));
}
});
extendingTimer.setInitialDelay(0);
extendingTimer.setDelay(100);
extendingTimer.setRepeats(true);
int lineCount = 0; //global
// timer calls the below
xLocation = (*a)[a->size()-1] * timeSoFar / duration ;
if(xLocation > (*a)[lineCount+1]){
lineCount++;
}
double m = ((*b)[lineCount+1] - (*b)[lineCount])/((*a)[lineCount+1]-(*a)[lineCount]);
double yIntercept = (*b)[lineCount]-m*(*a)[lineCount];
yLocation = m * xLocation + yIntercept;
xLocation = (yLocation - yIntercept) / m;
this is in c++ and using vectors but its the theory we want. This allows for multiple lines not just one.
The Java Robot class allows one to move the mouse as if the actual physical mouse was moved.
However, how does one move the mouse from Point1 to Point2 in a humane (and thus not instant) manner? Aka, how does one set the speed of movement?
If no such speed is possible with the Robot class, thus if the mouse can only be moved instantenously, what kind of "algorithm" should be used to mimic a human's mouse movement? Should it move the mouse pixel by pixel with a certain incrementing speed?
Here is a pretty good way here:
Consider start_x where your mouse starts and end_x where you are wanting it to end. Same for y
for (int i=0; i<100; i++){
int mov_x = ((end_x * i)/100) + (start_x*(100-i)/100);
int mov_y = ((end_y * i)/100) + (start_y*(100-i)/100);
robot.mouseMove(mov_x,mov_y);
robot.delay(10);
}
Hope that helps...
The Robot class has a delay(...) method that you can use to control movement from point to point. Try a few different alogorithms to determine what you like.
Rewrite Geoff's answer for easier understanding:
for (int i=0; i<=100; i++){
int mov_x = start_x + (end_x - start_x) * i/100;
int mov_y = start_y + (end_y - start_y) * i/100;
robot.mouseMove(mov_x,mov_y);
robot.delay(10);
}