I am trying to draw an Oval with a for loop iterating through a list of coordinates that each contain an x value and y value. Currently, it does not seem to be drawing anything after I start the program. It draws the first time, but when I try drawing when the program is running, it doesn't seem to be drawing.
Here is the code for drawing:
private void render(){
bs = display.getCanvas().getBufferStrategy();
if(bs == null){
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Draw Here!
DrawGrid(g);
g.fillOval(100, 100, 10, 10);//this seems to draw
for(int i = 0; i < points.size();i++){//this doesn't draw....
System.out.println(points.get(i));
g.drawString(points.get(i).toString(), points.get(i).x*100-5+100, points.get(i).y-5-300);
g.fillOval(points.get(i).x*100-5+100, points.get(i).y-5-300, 10, 10);
}
//End Drawing!
bs.show();
g.dispose();
}
If you need more details, I am using graphics from java.awt library. Also, I have done this in the past, but I don't know why it isn't working this time.
This part is your issue:
points.get(i).x*100-5+100
Specifically x*100
You are drawing off screen. We can see this by breaking it down:
Lets assume that you have a point of x=28.
Lets do the math on that:
For X = 28 you will have the following calc: (28 * 100) - (5 + 100) = 2695
That X point of 2695 looks very large to me. You would need a 4k screen or ultrawide screen to see it.
The solution:
Have a think about why you are using x*100, and reduce it so that the point fits on your screen. Also, if you have a small y point, then it will be in the negatives (Example: 15-5-300 = -290), and will probably draw above your screen and out of sight.
Related
So I'm creating a game using Javax.swing library for my uni coursework.
I have created a window and I have successfully written code to procedurally generate a game map.
However, I am unable to change the focus of the map. What I mean is that the map is always stuck in one corner of the screen. (IE: Location is set to 0,0, hence the Graphics g (the map) is put in that location going outwards.)
I would like to be able to move the "camera" so that different areas of the map can be viewed by the player.
Bellow I have pasted my method that draws the map onto the screen. Could anyone tell me what I could do to have the camera move at runtime. AKA: to shift the map left or right.
I thought of having a Graphics object that will hold the map, and then I'd only draw a subImage of that Graphics object, but considering how the map will be redrawn every frame (For animation purposes) that just means that I'll have even more graphics to redraw.
The map is 6,400 * 6,400 Pixels
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
for(int x = 0; x < OverworldMap.MAP_X_SIZE; x++){
for(int y = 0; y < OverworldMap.MAP_Y_SIZE; y++){
for(int layer = 0; layer < OverworldMap.MAP_LAYER_SIZE; layer++) {
g.drawImage(OverworldMap.getTileAt(x, y, layer).getSprite(), x * SPRITE_SIZE, y * SPRITE_SIZE, null);
}
}
}
} catch (Exception e) {
LauncherClass.printErrorLog(e);
}
}
The best / easiest way to solve this is to put a JScrollPane around your JPanel, and make the JPanel the size of your image. You don't need to worry about only repainting the right part of your image - Java is pretty smart about only drawing the parts that are on screen. Note that you can show or hide the ScrollBars, but if you hide them you need to add logic to activate scrolling through some other mechanism
You cannot store a Graphics object and use it later. It is only valid for the duration of the paint method to which it is passed.
You can, however, simply offset your painting:
Image sprite = OverworldMap.getTileAt(x, y, layer).getSprite();
g.drawImage(sprite, x * SPRITE_SIZE - playerX, y * SPRITE_SIZE - playerY, this);
(Notice that the last argument to drawImage should be this.)
I have an issue with drawing potentially hundreds of thousands rectangles with Java2D.
At first what I did was something along these lines:
private void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//Draw Graphics here
g.dispose();
bs.show();
}
I then realized after testing that this was horribly inefficient when having anything above 500 rectangles, so I thought that maybe drawing the graphics to a BufferedImage then displaying the BufferedImage would be more efficient, so I came up with this.
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
private void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = image.createGraphics();
//Draw Graphics here
g.dispose();
Graphics g2 = bs.getDrawGraphics();
g2.drawImage(image, 0, 0, width, height, null);
g2.dispose();
bs.show();
}
However this was still just as inefficient as the first way, I'm having trouble thinking of a better way to do this, and I'd prefer to stay away from something like OpenGL for this.
At between 500-1000 rectangles it gets really slow, and anything above that the program freezes very quickly.
So it would seem collision detection seems to be the main problem, rather than Java2D rendering. This is how I've handled the detection, it checks if two rectangles are touching on any side. If someone has a better approach to this I would appreciate it, because I'm seeing how inefficient this is.
public boolean collides(Entity e) {
Point2D upperLeftIn = new Point2D.Double(bounds.getX() + 1, bounds.getY());
Point2D upperRightIn = new Point2D.Double(bounds.getX() + 8, bounds.getY());
Point2D lowerLeftIn = new Point2D.Double(bounds.getX() + 1, bounds.getY() + 9);
Point2D lowerRightIn = new Point2D.Double(bounds.getX() + 8, bounds.getY() + 9);
Point2D upperLeftDown = new Point2D.Double(bounds.getX(), bounds.getY() + 1);
Point2D lowerLeftUp = new Point2D.Double(bounds.getX(), bounds.getY() + 8);
Point2D upperRightDown = new Point2D.Double(bounds.getX() + bounds.getWidth(), bounds.getY() + 1);
Point2D lowerRightUp = new Point2D.Double(bounds.getX() + bounds.getWidth(), bounds.getY() + 8);
Line2D top = new Line2D.Double(upperLeftIn, upperRightIn);
Line2D bottom = new Line2D.Double(lowerLeftIn, lowerRightIn);
Line2D left = new Line2D.Double(upperLeftDown, lowerLeftUp);
Line2D right = new Line2D.Double(upperRightDown, lowerRightUp);
if (e.bounds.intersectsLine(top)) {
return true;
}
if (e.bounds.intersectsLine(bottom)) {
return true;
}
if (e.bounds.intersectsLine(left)) {
return true;
}
if (e.bounds.intersectsLine(right)) {
return true;
}
return false;
}
Although I'm not sure how to handle the fact that the contents/goal of the question changed completely due to the edit...
To summarize: As it was pointed out in the comment (and you seem to have anticipated), the rendering of even thousands of rectangles should not be so much an issue in Java2D. Internally, it is using hardware support with DirectX or OpenGL, and you really have to spill lots of antialiased text and complex, textured or gradient-painted shapes onto the screen in order to really slow it down.
That being said, it's really not unlikely that the collision detection is the bottleneck here.
Presumably, the method that you posted is in the Entity class. And presumably, e.bounds is a Rectangle2D. In this case, you could simply test for intersections with
public boolean collides(Entity e) {
return this.bounds.intersects(e.bounds);
}
It is not clear what you wanted to achieve with the creation of the Line2D objects there, and you should probably explain this in words. (Maybe some sort of "threshold" around the actual bounds?). But you should keep in mind that the intersectsLine method can be computationally expensive, at least compared to the test that you actually want to do. You should try to boil this down to interval checks.
But even if you do this sort of (micro?-)optimizations to your collides method, the problem may be a more general one: From what you have written so far, one has to assume that you are testing each entity for collisions with each other entity, and this method is called in a loop like
for (int i=0; i<allEntities.size(); i++)
{
for (int j=i+1; j<allEntities.size(); j++)
{
Entity ei = allEntities.get(i);
Entity ej = allEntities.get(j);
if (ei.collides(ej)) handleCollision();
}
}
If this is the case, no optimization of the implementation will help you, because the problem lies in the asymptotic complexity: The number of intersection tests (that is, the number of calls to the collides-method) grows quadratically with the number of objects. For 500 objects, you'll have to do do ~125.000 calls to the method. That's already quite a lot, and could hardly be done 60 times per second. But for 5000 objects, you don't need 1.250.000 calls, but 12.500.000 - this is 100 times as many, and of course, impossible to do at 60 FPS.
There are sophisticated data structures for the (pairwise) collision detection of so many objects. Unfortunately, "sophisticated" here often means "horribly complicated to implement". Bounding Volume Hierarchies may be one approach that can help to accelerate the collision detection with reasonable effort. But if you have "many" and "small" objects that are in a "small" space, Spatial Hashing may be the more appropriate solution. You can quickly find tutorials/blog entries and sample code using this keyword, one example is at Spatial hashing implementation for fast 2D collisions, but there are several others.
I am programming a platformer game in Java. Everything works fine and there are no bigger problems, except the flickering on the screen when the Canvas is updated.
I'll roughly explain how my game "engine" works:
In my main method, I have a Loop, that is repeating itself 30 times a second:
while (play) {
Date delay_time = new Date();
delay_time.setTime(delay_time.getTime() + (int) (1000*(1.0/FPS)));
// Here is all the game stuff, like the motion of the player,
// function calling, etc.
Graphics g = can.getGraphics();
can.update(g);
while(new Date().before(delay_time)) {
}
}
My FPS variable is a static final int that is currently set to 30.
So i am updating my Canvas 30 time a second.
Play is a boolean, which controls if the game is still playing, or the player died.
Can is an instance of my class MyCanvas.java.
The Code of the paint() method looks like so:
if (Main.play) {
//NOW
//Draw the now Level Caption
//SIZE: 240
g2.setFont(new Font("Bank Gothic", Font.PLAIN, 240));
g2.setColor(new Color(Math.abs(bg.getRed() - 30), Math.abs(bg.getGreen() - 30), Math.abs(bg.getBlue() - 30)));
g2.drawString("LEVEL " + Main.lvl, 80, 80 + 300 - Main.groundY);
//Draw the ground
g2.setColor(haba);
g2.fillRect(0, Main.screenSize.height - Main.groundY, Main.screenSize.width, Main.groundY);
//Draw the level
g2.setColor(haba);
for (int i = 0; i < Main.LVLWIDTH; i++) {
for (int j = 0; j < Main.LVLHEIGHT; j++) {
if (Main.level[i][j] == '1') {
g2.fillRect(i*(Main.BLOCK_X), (j - Main.LVLHEIGHT)*(Main.BLOCK_Y) + Main.screenSize.height - Main.groundY, Main.BLOCK_X, Main.BLOCK_Y);
}
}
//More drawing stuff...
}
So, as you can see, I am updating quite a lot - 30 times a second. This leads to the problem that my game (which is playing in fullscreen mode BTW) flickers all the time. How do solve that problem? Is a Bufferstrategy the right way? And if yes, how should I do it? Can you please explain the Bufferstartegy or provide links that have great tutorials or explanations, which or not to technical and non-beginner friendly? That would be great.
The BufferStrategy class solved my problem. Here is a good link to it, with a well made example of how to use it:
http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferStrategy.html
I'm working on trying to make an image move in processing, but the image is leaving a trail. The important part which is tripping me up is that I cannot declare the background in draw(), because I have other functions which place images. Here is the relevant code:
void setup()
{
size(752,500);
background = loadImage("prairie.jpg");
background(background);
noStroke();
animal = loadImage("squirrel.png");
bird = loadImage("bird.gif");
rock = loadImage("rock.png");
cloud = loadImage("cloud.png");
jeep = loadImage("jeep.png");
flower = loadImage("flower.png");
}
float jeepX = 752;
float jeepY = 250;
float size = 100;
void draw()
{
image(jeep,150,350,125,125);
image(jeep,jeepX,jeepY,size,size);
jeepX--;
jeepY = jeepY + .25;
size += .25;
image(jeep,jeepX + 1,jeepY - .25, size -.25, size - .25, 0,0,0,0);
if(jeepY > height)
{
jeepX = 752;
jeepY = 250;
size = 100;
}
}
This is for lab and the TA didn't know how, and I didn't have a chance to ask the professor yet.
If no one knows the answer and/or it has something to do with other functions (which place images), i'll post the relevant code.
For moving objects not to leave a trail, you must first clear the frame before redrawing the picture.(don't forget to reset the background if you don't have one)
As it is, it draws one jeep, then another on top of it.
If you don't want the trail, you got clear the background. If not completely, at least part of it, or redraw every image not supposed to move every frame.
Like this:
Sample Code
PImage bg, still, moving;
void setup() {
while ( bg == null) {// got wait as size depends on this...
println("loading bg image...");
bg = loadImage("http://dc489.4shared.com/img/f9EaWk5w/s3/13757197c08/Black_Background_Metal_Hole_-_.jpg");
}
size(bg.width, bg.height);
still = loadImage("http://www.renderosity.com/mod/bcs/photos/Thumb85619.jpg");
moving = loadImage("https://cdn1.iconfinder.com/data/icons/humano2/128x128/apps/alienblaster.png");
}
void draw() {
background(bg);
image(still, 100, 100);
image(moving, 200, frameCount%height);
}
You need to redraw your background in the 'draw' method. To do this, simply add the following line of code to your 'draw' method:
background(red,green,blue);
You can use the Colour Selector in Processing (found under Tools) to find the correct rgb code for the colour you want.
The reason for this is that the draw method is run 60 times a second, whereas the 'setup' method is only run once when the program is executed. As such, when you move the image, if the background colour is not in the 'draw' method, then it will not be redrawn when the image is moved, thus leaving a trail.
So, my situation is that I am drawing a lot of concentric circles, and to make this more efficient I am wanting to only draw 1/8 of the circle and then mirror/rotate the rest of the drawing. To be clear, let's say I have the following code:
for(int i = 0; i < end; i++) {
posX = calcX(i);
posY = calcY(i);
length = calcLength(i);
g2.fillArc(posX, posY, length, length, 0, 45);
}
// mirror/rotate 7 times...
Is this even possible? I know you can for an Image, but this seems a lot more tricky.
Thanks in advance for your help!
EDIT: g2 is a Graphics2D object.
EDIT 2: So, lets say I have the following slice. Is there a way to take this whole slide (drawn with "fillArc") and copy it 7 times and make a full circle:
EDIT 3: Fixed code to match what I'm saying.
I think g2 is a Graphics2D object?
Then you can use
g2.setTransformation();
And use a AffineTransformation to rotate the image. Altough it should be more efficient to use
g2.drawOval(...);
in order to draw circles.