How to draw a two dimensional graphic at Java? - java

I have 2 different lists. Each of them holds x and y value pairs(they have both positive and negative values). How can I draw them on a 2D axis? I want to put points for every value and they will blue for first list and red for second list.
My lists' type:
List<List<Double>>
List<Double> inside of List<...> has 2 variables, first of it for x value and the second one is for y value.
However just I need to how to draw a two dimensional graphic at Java(desktop application) and put points wherever I want, improving code for my variables is less important.
PS:
I want the more and more simple of that kind of graphic:
Something like:

you could use a library like http://www.jfree.org/jfreechart/ (LGPL-License) there are lots of examples around the web, and it's quite easy to use.
here's an example, that seems to match your requirements:
http://www.java2s.com/Code/Java/Chart/JFreeChartMarkerDemo1.htm

Assuming you are using Swing with a panel, you can use the following:
public class JImagePanelExample extends JPanel {
private BufferedImage image;
private Graphics2D drawingBoard;
private int x, y; // Image position in the panel
// Let's assume image is a chart and you need to draw lines
public JImagePanelExample(BufferedImage image, int x, int y) {
super();
this.image = image;
// Retrieving a mean to draw lines
drawingBoard = image.createGraphics();
// Draw what you need to draw (see other methods too)
drawingBoard.drawLine(0, 10, 35, 55);
}
// Called by Swing to draw the image in the panel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, x, y, null);
}
}
If you don't want to use Swing and you just need to draw in 2D, focus on BufferedImage and Graphics2D only.

There is a Java 2D API: http://java.sun.com/products/java-media/2D/ and many charting libraries easily found with a web search.

Related

Why drawing pixels directly is slower than drawing data in a BufferedImage?

Currently I'm trying to create something to display a "2D view" for a Grid which can be used for various proporses, such as a simple 2D game.
After doing a wrap work with a simple Core class (this holds all information to my visual stuff, including pixels values for sprites) I started the visual work. As my aim is to do this with plain swing/awt in Java I just created a custom JComponent to this.
In my JComponent I tried some approaches and decided to test draw my pixels info in a BufferedImage and at other hand draw the pixels directly in Graphics object.
Looking through internet I found some ways to draw a pixel/dot on screen, like this. In this case, I wrapped this in a method:
private void drawSpritePixels(ArrayList<Spr.Pixel> pixels, int startX, int startY, Graphics2D g) {
for (Spr.Pixel p : pixels){
g.setColor(p.color);
g.fillRect(p.x + startX, p.y + startY, 1, 1);
}
}
For drawing my data onto a BufferedImage, I'm using this:
public BufferedImage spriteImage(int spriteAddress) {
BufferedImage img = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration()
.createCompatibleImage(32, 32, Transparency.TRANSLUCENT);
for (Pixel p : getSpriteInfo(spriteAddresses.get(spriteAddress))) {
img.setRGB(p.x, p.y, p.color.getRGB());
}
return img;
}
As title says, the performance was better using BufferedImage approach. Im my tests BufferedImage takes 40ms to finish while Pixels takes 200ms+ to the same amount of "work".
Then, why this is so different? Should do I avoid any iterations in pixels approach?

Java game 2D overlapping shadows with Swing

I am currently developing a 2D Java game using Swing as my primary drawing component. Every object has a shadow (BufferedImage) but every shadow overlaps other shadows. Is it possible to only have the shadows not overlap each other? Because I still want the shadows to draw over the player if the object is beneath it, and not if the object is above of the player. Here is a picture for clarity:
I have looked at alpha compositing, I guess I need Source Out? I also thought of having all the shadows (with no transparency) draw on one layer and then draw it with transparency but then it won't draw over the player and other objects like before.
I have a Draw object which is a JPanel and overrides the paintComponent method. Within this method I draw the floor of the current room and then I iterate over the list of objects that belongs to the current room and call each objects' draw method to draw everything.
The object draw method:
public void draw(Graphics g) {
if (visible && checkInScreen()) {
// The required drawing location
int drawLocationX = getX() - globalCameraX;
int drawLocationY = getY() - globalCameraY;
if (shadow) {
g.drawImage(shadowImages.get(imageIndex),
drawLocationX + shadowOffset.x + (getImageWidth()/2),
drawLocationY + shadowOffset.y, null);
}
g.drawImage(images.get(imageIndex), drawLocationX, drawLocationY, null);
//Collisionbox
if (SHOW_COLLISION_BOXES){
g.setColor(Color.WHITE);
g.drawRect(drawLocationX + getCollBoxX(), drawLocationY + getCollBoxY(), getCollBoxW() - getCollBoxX(), getCollBoxH() - getCollBoxY());
}
}
}
My apologies if this question has already been asked but I couldn't find something similar like this.
What I would do to solve this is to have a shadow-layer bitmap. By which I mean:
have your shadow textures saved as a 2D array of boolean values (representing the position of a shadow pixel).
What you can do with this is to then logically or the shadow maps together to create a single layer, which can be layered behind the tree textures to create the shadows.
You may want to change the booleans to floats to represent the colour/intensity of the shadow, then have a larger calculation to merge the shadows together.
The below ShadowMap class is used to store the data for each shadow:
class ShadowMap {
public int xPos, yPos;
public boolean[][] array;
public ShadowMap(int xPos, int yPos, boolean[][] array) {
this.xPos = xPos;
this.yPos = yPos;
this.array = array;
}
}
The ShadowLayer class creates a 2D array for the entire screen, containing if a shadow is present for each pixel:
class ShadowLayer {
public static boolean[][] array = new boolean[SCREEN_WIDTH][SCREEN_HEIGHT];
public static makeNew(ShadowMap[] shadows) {
for (int x = 0; x < SCREEN_WIDTH; x++) {
for (int y = 0; y < SCREEN_HEIGHT; y++) {
array[x][y] = false;
}
}
for (ShadowMap map : shadows) {
for (int i = 0; i < SCREEN_WIDTH; i++) {
for (int j = 0; j < SCREEN_HEIGHT; j++) {
// Logical or such that the pixel at (x, y) has a shadow
// if any shadow map also has a shadow at pixel (x, y)
array[i + map.xPos][j + map.yPos] |= map.array[i][j];
}
}
}
}
}
Using this ShadowLayer class, you just need to darken each pixel on the screen if the ShadowMap has a shadow on the same pixel:
public static Color ajustPixelForShadows(int x, int y, Color pixel) {
return ShadowMap.array[x][y] ? pixel.darken() : pixel;
}
I admit I'm not familiar with Swing so I'm not sure it is possible with that specific interface but the below solution could be used in a variety of 2D graphics engines.
You'll need an off-screen "shadow layer" to draw to that matches the screen dimensions. Initialize the shadow layer to being pure white.
For each object you draw from back to front (y-sorting), do the following, in order, with the shadow layer:
Draw the object's shadow shape in a single solid dark grey color to the shadow layer
Draw the object itself to the shadow layer as a pure white sprite (i.e. all non-transparent pixels in the object's bitmap are white)
Of course, also draw the object itself to the screen.
Then, once all objects have been drawn to both the screen and the shadow layer, draw the shadow layer to the screen using multiply blending. The multiply blend guarantees shadows will darken whatever they are drawn over (unlike alpha blend which, with very light shadows, could potentially actually lighten the colors they are drawn over). It will also make the pure white portions of the layer do nothing, which is what you want.
The above steps mean that after each object draws a shadow, it erases any shadows that would be underneath it in the final scene when it draws itself in white to the shadow layer. Therefore it won't cast a shadow on itself, and objects won't cast shadows over other objects that are technically in front of them.
Objects will still cast shadows onto other objects that are behind them as you wanted, since any parts of the shadow that haven't been erased by an overlapping object will still apply (or if they are erased, will be potentially re-drawn by a later object). And, since you are drawing the shadows as a single non-translucent color to the shadow layer, multiple shadows overlapping won't affect each other either, which was of course the main point.
You could modify this technique depending on what you have available. For example, instead of white you could use a fully transparent shadow layer initially and an "erase" blend mode [(src * 0) + (dst * (1 - srcAlpha))] to draw the objects that erase shadows underneath them. You could then use alpha instead of multiply blend if you prefer for drawing the shadow layer to the screen.

Translate/Rotate/Move a graphics object without messing up the whole screen

I'm coding a GUI that will be doing some graphics translations/rotations, etc.
My problem is that when I try to translate my graphics,
(a) The entire screen translates instead of my one little painted area
(b) The old paint stays there, leaving a big paint blob instead of a translated image
(c) If I use the clearRect method to allow me to avoid (b), the entire screen goes white and (a) is still a problem
my DrawPanel class (I called it "LaunchTubeImage" for whatever reason)
private class LaunchTubeImage extends JPanel {
private Color colour;
public LaunchTubeImage(Color color) {
super();
this.colour = color;
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,
tubeImage.getSize().height - 50);
g.setColor(colour);
g.clearRect(0,0,getWidth(),getHeight());
g.fillRect(tubeImage.getSize().width/2,
tubeImage.getSize().height - 100 , 10, 50);
}
}
where this is called in my code
tubeImage = new LaunchTubeImage(Color.MAGENTA);
angle.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
tubeImage.repaint();
}
});
Case 1: Comment out clearRect in that 1st block of code I posted
http://i58.tinypic.com/2d1l5w2_th.png
Black background as desired. Not rotated yet. Looks good so far.
http://oi60.tinypic.com/1zw1sm.jpg
Rotated it with my JSpinner... you see that the previous location was not removed (and note how my buttons randomly doubled and put themselves at the top of the screen).
Case 2: Keeping in the clearRect method
oi57.tinypic.com/2s84307.jpg
Layout is fine so far, but I wanted the background to be black
oi57.tinypic.com/4rde8x.jpg
Yay! It rotated. But note the weird behavior of that random "15" that appeared in my top right corner
oi58.tinypic.com/vymljm.jpg
And finally... when I resize the window you see that my entire screen was rotated - not just the pink image I wanted to rotate
Tips/fixes/advice? Thanks!! I hope I've provided enough information
(P.s. if you insist on us asking clear/useful questions.... then DON'T limit the number of images you can post... :/ )
The first line of an overridden paintComponent method should usually be super.paintComponent(g). On a JPanel, this will cause the drawing area to be cleared with the background color. If you want to clear the background with a different color, you can do this by manually filling a rectangle (clearRect is discouraged, see the JavaDoc), but of course, this has to be done before applying any transform.
So your method should probably look like this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(colour);
g.fillRect(0,0,getWidth(),getHeight());
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,tubeImage.getSize().height - 50);
gg.fillRect(tubeImage.getSize().width/2,tubeImage.getSize().height - 100 , 10, 50);
}

2D Tile Engine (World Generation) - Beginner

I am a beginning Java Game Developer. For my first game, I'm making something along an advanced version of Minicraft
by Notch. However I have absolutely clue how to make a 2D Tile-Based World Generator.
Would anyone mind explaining how I would do this and maybe a link or two to some YouTube Videos?
I am using Eclipse EE for Java Developers.
Also I can't seem to resize my window to make the pixels larger. The image is 16 x 16 pixels, however I'd like to display it larger like minicraft (link above)
Here is the code for Skeleton.java (which is the framework ('Skeleton') of the game)`
package code;
import java.awt.Graphics;
public class Skeleton extends Loop{ //Should extend Applet?
public void init(){
Thread th= new Thread(this);
th.start();
offscreen = createImage(120,160); // 120, 160
d = offscreen.getGraphics();
addKeyListener(this); //15:43
}
public static final int HEIGHT = 120; //Original Height/Width= "120 x 160"
public static final int WIDTH = 160;
public static final String TITLE= "Test Game BETA";
public static final int SCALE = 3;
public void paint(Graphics g) {
d.clearRect(0, 0, 160, 120); //Error Here, Scale perhaps? -Disregard //0,0,160,120
d.drawImage(him, x, y, this); //12:17 http://www.youtube.com/watch?v=XmRD0PlAXEY
g.drawImage(offscreen, 0, 0, this);
}
public void update(Graphics g){
paint(g);
} //Finished at 15:33 ERROR w/ the circle -Fixed
}
//2D Tile Engine Must be Created
I am working on a project that is almost identical to this. The way I generate the worlds, I have a two-dimensional array of tiles, and a method that populates the array with tiles. The way the world is generated, I place a grass tile in each column, followed by a randomly determined number of dirt tiles, followed by stone tiles until the bottom of the world. Then, for the next column, I place a grass tile at a y-coordinate that is between -2 and +2 tiles from the previous grass's y-coordinate, and fill the rest of the column as before. Continue until you get to the end of the array.
To rescale images, I use this method
public void drawRezizedImage(Graphics g, Image image, int x, int y, int sizeX, int sizeY){
image.getScaledInstance(200, 200, Image.SCALE_SMOOTH);
g.drawImage(image, 0, 0, null);
}
This will simply draw a rescaled version of your, in this case 16 by 16px image.
Hope this was, what you were looking for.

How to paintComponent to display objects in Java?

Okay, so I have a GameField class, and a GameObject class and a Panel class.
The GameObject class describes an object, which has an x and y position, width and height, and x and y direction (in which it is currently moving). The GameField class has a few different instances of these objects, some stored by themselves, and some stored in primitive arrays.
The Panel class is supposed to display these objects on the screen. I used JPanel for this.
However, when it comes to actually displaying them on the screen, I'm a bit lost. I need to implement a function called paintComponent(Graphics graphics), which takes in a Graphics object.
To start, I want to display all the objects on the screen, and set their colour. Their size, position, etc. are handled elsewhere. How can I use these attributes to set the actual objects to have a size, position and direction?
I may need to override the paintComponent function to display all the objects in GameField.
If you could help me out with some code, that'd be great.
I'm not quite clear on what you mean by "their size, position, etc. are handled elsewhere". For now, let's assume that you have approximately the following structure (fields and other methods ommitted for clarity) :
class GameObject {
java.awt.Color getColor() { ... }
java.awt.Point getPosition() { ... }
java.awt.Point getDirection() { ... }
java.awt.Dimension getSize { ... }
}
class GameField {
List<GameObject> getGameObjects() { ... }
}
class Panel extends JPanel {
private GameField getGameField() { ... }
#Override
public void paintComponent(Graphics g) {
// this is where the GameObjects must be painted
}
}
The paintComponent method is responsible for the screen representation of the Panel class. If you override it, you have just won that responsibility from it. Luckily, drawing is - if tedious - rather simple. You asked about that Graphics parameter. Very simply put, it is set for you by the magic of Java and gives you a toolbox to use for drawing.
First, you will want to have a clean slate whenever the panel is repainted. You cannot delete anything once it is painted, but you can easily paint the entire panel in a background color of your choice.
g.setColor(Color.white); // everything that is now painted will be white
g.fillRect(0, 0, getWidth(), getHeight()); // fills the entire area with the set color
Now, for each GameObject you have, let's place rectangle in the objects' defined color and size on the screen, with it's center on the object's position.
for (GameObject object : getGameField().getGameObjects()) {
g.setColor(object.getColor());
g.fillRect(object.getPosition().x - (object.getSize().x / 2), object.getPosition().y - object.getSize().y / 2, object.getSize().x, object.getSize().y);
}
The fillRect method requires the first two arguments to be the top-left corner of the rectangle. So to have it centered on the object's position, we subtract half the size from the position for the x and y values respectively. Now you have, for every GameObject, a rectangle of the right diameter in the object's color at the right position.
You should read up on the javadoc on java.awt.Graphics to find out how to draw other stuff, maybe image sprites or lines for the direction or something. It is cumbersome but doable.

Categories