Scaling Graphics (Beginning Java Programmer) - java

I am Chris.
I am fairly new to coding, I don't know many terms, this is my third and most successful attempt at learning Java. Yeah, It didn't work out so much was I was younger.
Anyhow, I am trying to create a game but I'm having a slight problem.
I made a 16 x 16 image as my character, however - as expected- it shows up as fairly small.
I have absolutely no clue how to make it larger.
Here is the code:
package code;
import java.awt.Graphics;
public class Skeleton extends Loop{ //Should extend Applet?
private static final long serialVersionUID = 1L;
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

The drawImage function can take a destination size, and it will scale your image for you:
drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
Reference: http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html

Related

How to increase the size of a circle within a circumference using the mouse wheel?

Why this code doesn't work as it should work?, Could you help me to correct it, I'm new in Java, I've been practically all day making some Java exercises and I'm about to give up with this exercise, it's almost ready but still needs some corrections, basically, the objective of the program is that when the user places the pointer inside each circumference and when the user moves the mouse wheel, the internal circles of colors change in size according to the parameters that are specified in the main class and can never exceed the size of the circumference, the exercise is a bit more complicated because, In addition, circumferences and internal circles of colors should change in size and shape if the size of the window is changed. Only the second Class can be modified because the main class is already given.
I would appreciate it if you could help me, by the way, I am sorry if I made some grammatical errors, English is not my native language
package Hw03_Balloon;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
public class BalloonTest extends JFrame {
private Balloon ct_red, ct_green, ct_blue;
public BalloonTest() {
setTitle("Balloon Test");
setSize(450, 250);
setupWidgets();
setupEvents();
setVisible(true);
}
private void setupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void setupWidgets() {
ct_red =new Balloon(100, 0, 100, Color.RED, 1);
ct_green =new Balloon(20, 0, 100, Color.BLUE, 5);
ct_blue =new Balloon(20, 0, 100, Color.ORANGE, 10);
setLayout(new GridLayout(1,3));
add(ct_red);
add(ct_green);
add(ct_blue);
}
public static void main(String[] args) {
new BalloonTest();
}
}
And this is the second class I used
package Hw03_Balloon;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JComponent;
public class Balloon extends JComponent{
private int value;
private int min;
private int max;
private Color col;
private int speed;
public int r1;
public Balloon(int value, int min, int max, Color col, int speed) {
this.value=value;
this.min=min;
this.max=max;
this.col=col;
this.speed=speed;
}
public void paint(Graphics g) {
int w =getWidth();
int h =getHeight();
int x=w/2;
int y=h/2;
int r1=(int) ((double)value/100*24*w/29);
int r2=(int) ((double) value/100*40*h/71);
System.out.println(r1);
x = x-(r1/2);
y = y-(r2/2);
g.setColor(col);
g.fillOval(x, y, r1, r2);
g.setColor(Color.BLACK);
x=w/2;
y=h/2;
r1=24*w/29;
r2=40*h/71;
x = x-(r1/2);
y = y-(r2/2);
g.drawOval(x, y, r1, r2);
this.r1=r1;
setupEvents();
}
private void setupEvents() {
addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent ev) {
if(value+ev.getWheelRotation()>=0 && value+ev.getWheelRotation()<=r1) {
value -= speed*ev.getWheelRotation();
if (value<=0) value=0+1;
if (value>=r1) value=r1-1;
repaint();
}
}
});
}
}
In Ballon#setupEvents you create and add a mouse wheel listener to the component, right? In a component you can multiple listeners (in your case, mouse wheel) which are going to be fired when mouse wheel is moved. You call this method (Ballon#setupEvents) inside JComponent#paint() method. Therefore, every time paint() method is called, a new mouse wheel listener is added to the component. The result is that your component has multiple listeners. That's why you get this strange behavior.
Solution: Have only one mouse wheel listener added to the component. Also, do not #Override paint() method. #Override JComponent#paintComponent(Graphics g) method.
About circles having bigger bounds than the black one:
I searched it a bit, and i can say you over-complicate it. As far as i can understand from these two lines:
int r1=(int) ((double) value/100 * 24*w/29);
int r2=(int) ((double) value/100 * 40*h/71);
Your variable value is expressed into percentage. And here comes the "over-complicated" part. You just have to adjust this percentage by speed*mousewheelrotation on each mouse wheel event. Simple as that.
P.S: I wish i could explain more what you did wrong, but i had hard time to find your logic, and i do not think it is necessary to make things complex.
Balloon.class:
public class Balloon extends JComponent{
private int value;
private int min;
private int max;
private Color col;
private int speed;
public int r1;
public Balloon(int value, int min, int max, Color col, int speed) {
this.value=value;
this.min=min;
this.max=max;
this.col=col;
this.speed=speed;
setupEvents(); //Call only 1 time in constructor
this.r1=24*(getWidth()/2)/29; //Declare it one time
}
#Override
public void paintComponent(Graphics g) {
int w =getWidth();
int h =getHeight();
int x=w/2;
int y=h/2;
int r1=(int) ((double)value/100*24*w/29);
int r2=(int) ((double) value/100*40*h/71);
System.out.println(r1);
x = x-(r1/2);
y = y-(r2/2);
g.setColor(col);
g.fillOval(x, y, r1, r2);
g.setColor(Color.BLACK);
x=w/2;
y=h/2;
r1=24*w/29;
r2=40*h/71;
x = x-(r1/2);
y = y-(r2/2);
g.drawOval(x, y, r1, r2);
}
private void setupEvents() {
addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent ev) {
value -= speed*ev.getWheelRotation();
if (value<=0)
value=speed; //Minimum
if (value>=100)
value=100; //Maximum
repaint();
}
});
}
}

how do you draw a line that resize when window size change? [duplicate]

I've written an app that custom draws everything inside paint() based on fixed pixel positions. Then I disabled resize of the frame so its always visible.
However, now I would like to be able to resize it but I dont want to change my drawling code. I was hoping I could grab the 300x300 square of the Graphics g object and resize it to the JFrame current size after all of my drawling code, but I have no idea what I'm doing.
Here sample code. In this I want the 100x100 square to remain in the middle, proportionate to the resized JFrame:
package DrawAndScale;
import java.awt.Color;
import java.awt.Graphics;
public class DASFrame extends javax.swing.JFrame {
public DASFrame() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.setSize(300, 300);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DASFrame().setVisible(true);
}
});
}
#Override
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fill3DRect(100, 100, 100, 100, true);
}
}
Thanks.
Assuming you rename your method that paints for 300x300 as paint300, define a buffered image:
#Override public void paint(Graphics g) {
Image bufferImage = createImage(300, 300); // empty image
paint300(bufferImage.getGraphics()); // fill the image
g.drawImage(bufferImage, 0, 0, null); // send the image to graphics device
}
Above is when you want to draw at full size (300x300).
If your window is resized:
#Override public void paint(Graphics g) {
Image bufferImage = createImage(300, 300);
paint300(bufferImage.getGraphics());
int width = getWidth();
int height = getHeight();
CropImageFilter crop =
new CropImageFilter((300 - width)/2, (300 - height)/2 , width, height);
FilteredImageSource fis = new FilteredImageSource(bufferImage, crop);
Image croppedImage = createImage(fis);
g.drawImage(croppedImage, 0, 0, null);
}
The new classes are from from java.awt.image.*.
I didn't test this code. It's just to send you in the right direction.
if you want to painting Custom paint then look for JLabel or JPanel and including Icon/ImageIcon inside, simple example about that
import java.awt.*;
import javax.swing.*;
public class MainComponentPaint extends JFrame {
private static final long serialVersionUID = 1L;
public MainComponentPaint() {
setTitle("Customize Preffered Size Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponent());
pack();
setMinimumSize(getSize());
setPreferredSize(getSize());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
setVisible(true);
}
});
}
public static void main(String[] args) {
MainComponentPaint main = new MainComponentPaint();
main.display();
}
}
class CustomComponent extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
for (int i = 0; i < Math.max(w, h); i += 20) {
g.drawLine(i, 0, i, h);
g.drawLine(0, i, w, i);
}
}
}
Not an expert, but you could just scale the Graphics2D object (the passed Graphics is in fact a Graphics2D instance), where the x and y ratios are the ratios of the fixed size you chose to draw and the actual size of the frame.
See http://download.oracle.com/javase/6/docs/api/java/awt/Graphics2D.html#scale%28double,%20double%29
You could do this with some math.
public void paint(Graphics g){
int height = 100;
int width = 100;
int x = (this.getWidth() / 2) - (width / 2);
int y = (this.getHeight() / 2) - (height / 2);
g.setColor(Color.BLACK);
g.fill3DRect(x, y, width, height, true);
}
Or if you wanted to keep the width and height of the box with the same proportion, use int width = this.getWidth() / 3; and int height = this.getHeight() / 3.
The other option is to use Graphics2D.scale(), as JB pointed out, the passed Graphics object is actually a Graphics2D object.

Java2D Unacceptable Frame Rate

Java2D Game Running 20-30 FPS
I am writing a java2D game that as of now has an almost perfect memory footprint running only at around 2% of about a 4GB usable RAM space. The problem is the game only is running at around 20-30 fps just from rendering the character and the surrounding environment. I read already something about utilizing the GraphicsConfiguration, but when I tried that my fps soared right up to 120-130 fps while my memory increased to 70-80% and the frame was frozen in one place even if i moved the character. At this point I am stuck. I assume it has something to do with how many times i call g2d.fillRect() because after removing an area that's being referenced the game seems to speed up. The game seems to run smoothly at 20-30 fps, but I need to fix this otherwise my viewable gameobject painter loop will reduce my game to nothing but lag.
Rendering Method With Clipping Areas
private void renderEnvironment(Graphics2D g2d){
for(int paint_index = 0; paint_index < paint_textures.size(); paint_index++){
TexturePaint current_paint = paint_textures.get(paint_index);
//Area a = new Area(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));
//a.intersect(new Area(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint))));
g2d.setPaint(new TexturePaint(current_paint.getImage(), new Rectangle(CamX, CamY, current_paint.getImage().getWidth(), current_paint.getImage().getHeight())));
g2d.setClip(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint)));
//g2d.fill(a);
g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight());
}
for(int paint_index = 0; paint_index < animated_textures.size(); paint_index++){
TextureAnimation current_paint = animated_textures.get(paint_index);
//Area a = new Area(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));
//a.intersect(new Area(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint))));
g2d.setPaint(new TexturePaint(current_paint.animatedPaint().getImage(), new Rectangle(current_paint.animatedPaint().getAnchorRect().getBounds().x + CamX, current_paint.animatedPaint().getAnchorRect().getBounds().y + CamY, current_paint.animatedPaint().getImage().getWidth(), current_paint.animatedPaint().getImage().getHeight())));
g2d.setClip(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint)));
//map_graphics.fill(a);
g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight());
}g2d.setClip(null);
g2d.drawImage(character_sprite.spriteImage(), host_frame.getWidth() / 2, host_frame.getHeight() / 2, host_frame);
for(int paint_index = 0; paint_index < global_textures.size(); paint_index++){
TextureAnimation current_paint = global_textures.get(paint_index);
g2d.setPaint(new TexturePaint(current_paint.animatedPaint().getImage(), new Rectangle(current_paint.animatedPaint().getAnchorRect().getBounds().x + CamX, current_paint.animatedPaint().getAnchorRect().getBounds().y + CamY, current_paint.animatedPaint().getImage().getWidth(), current_paint.animatedPaint().getImage().getHeight())));
//g2d.setClip(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));
g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight());
}
}
EDIT : TextureAnimation.java
public class TextureAnimation implements ActionListener {
private final Action behavior;
private final BufferedImage image;
private final Component host;
private TexturePaint paint;
private final Timer t;
private final boolean isGlobal;
public int x;
public int y;
public TextureAnimation(Action a, BufferedImage i, Component c, boolean global){
isGlobal = global;
behavior = a;
image = i;
host = c;
paint = new TexturePaint(image, new Rectangle(0, 0, image.getWidth(), image.getHeight()));
t = new Timer(300, this);
t.setInitialDelay(0);
}
public void playAnimation(){
t.start();
}
public Boolean isGlobal(){
return isGlobal;
}
public void delayAnimation(int ms_delay){
t.setInitialDelay(ms_delay);
t.restart();
}
public void setIntervalDelay(int ms_delay){
t.setDelay(ms_delay);
}
public void setTilePosition(int x, int y){
paint = new TexturePaint(image, new Rectangle(Gscale.setX(x), Gscale.setY(y), Gscale.setWidth(image.getWidth()), Gscale.setHeight(image.getHeight())));
}
public TexturePaint animatedPaint(){
return paint;
}
#Override
public void actionPerformed(ActionEvent e) {
behavior.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
//host.repaint(0,0, host.getWidth(), host.getHeight());
}
}
Researched Link
Java2D Performance Issues
Note : The Graphic2D parameter is taking on the graphics of the JPanel itself. So shouldn't java already create a Compatible image for me?

Painting Yellow on White using Java Graphics

My application performs data visualization using gray-scale "heat map". Above it I need to paint time axis in yellow color. It looks good on black background, but becomes invisible on white background (see attached image). How to make it visible regardless of background?
Here is how I paint the timestamps:
g.setColor(Color.yellow);
g.drawString("12:43:15", x, y);
where g is java.awt.Graphics object
What about XOR'ing your Color. For e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
#SuppressWarnings("serial")
public class XorEg extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W / 4;
private static final float SIZE = 24f;
private String text = "Hello world, how's it going? ";
public XorEg() {
setFont(getFont().deriveFont(SIZE));
for (int i = 0; i < 2; i++) {
text += text;
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
int x = 0;
int y = 0;
int width = getWidth() / 2;
int height = getHeight();
g.fillRect(x, y, width, height);
g.setColor(Color.white);
x = width;
g.fillRect(x, y, width, height);
g.setXORMode(Color.blue);
g.drawString(text, 10, PREF_H / 2);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
XorEg mainPanel = new XorEg();
JFrame frame = new JFrame("XorEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
which shows:
You could "outline" the text (in black for example)
For example...
As demonstrated in Assigning a image to a String
Put a rectangle behind the text, and paint it a dark translucent color.
E.G. as seen in this answer (OK that is 'dark on light' as opposed to 'light on dark' but ..Batteries Not Included).
Here is another example that uses the same 'outline' approach as mentioned by #MadProgrammer.
Use another color that works good with black and white or detect lower color and change text color based on that, which is a better approach

Drawing more than one rectangle with Java (awt)

Here's my code:
class Ramka extends JFrame
{
public static final int SZEROKOSC = 800;
public static final int WYSOKOSC = 600;
Container powZawartosci = getContentPane();
public Ramka()
{
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
}
public void addRectangle(int startX, int startY, int sizeX)
{
drawRectangle rect = new drawRectangle(startX, startY, sizeX);
powZawartosci.add(rect);
}
class drawRectangle extends JPanel
{
private int a, startX, startY;
public drawRectangle(int startX, int startY, int a) // square
{
this.a = a;
this.startX = startX;
this.startY = startY;
}
public void paintComponent(Graphics g)
{
Rectangle2D rect = new Rectangle2D.Double(startX, startY, a, a);
Graphics2D g1 = (Graphics2D) g;
g1.draw(rect);
}
}
public class Main
{
public static void main(String[] args)
{
Ramka ramka = new Ramka();
ramka.addRectangle(200, 200, 50);
ramka.addRectangle(100, 100, 100);
ramka.addRectangle(300, 300, 150);
ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ramka.setVisible(true);
}
}
What I want it to do is draw three rectangles (set aside the functionality and sense of doing so, I'm still just learning).
But it draws only the last one, starting at 300 and 300. I don't really understand the paintComponent thing...
Thanks in advance for any help,
Paul
I beleive that you are adding three JPanels on top of each other. This seems like an odd way to draw rectangles, but with this design, you need to use a LayoutManager.
Check out this link, and try to learn. The code below should do the trick though.
...
Container powZawartosci = getContentPane();
public Ramka()
{
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));//Only this line is inserted.
}
public void addRectangle(int startX, int startY, int sizeX)
{
drawRectangle rect = new drawRectangle(startX, startY, sizeX);
powZawartosci.add(rect);
}
...
In your JPanel derivative, you can keep track of the Rectangles that you need to draw. I am writing the code below spontanously, so check for errors first.
class RectangleDrawer extends JPanel{
ArrayList<Rectangle> rList = new ArrayList()<Rectangle>;
public void addRectangle(Rectangle rect){
rList.add(rect);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i=0; i<rList.size(); r++){
g.drawRectangle(rList.get(i));
}
}
}
The problem basically is that you're using two different levels of abstraction here.
In the first, you are adding a component to your JFrame, which is fine at some point.
You're adding your "DrawRectangle" instance, just the same way you would add a new button, a label or another panel. The problem comes when you add components in the same position. JFrame's main panel ( the content pane ) uses a "Border" layout manager that places the component in the middle if you don't add any constraint.
As a convenience, BorderLayout interprets the absence of a string specification the same as the constant CENTER
So, this line:
powZawartosci.add(rect);
Always adds your component in the "center", overriding the previous one. That's why you only saw one rectangle.
The second level of abstraction used here is painting the component yourself. This is low level and you have to tell the component who to draw each line and where.
That's fine, but if you want to draw several rectangles in the same component, you have to hold the references for each one ( using a collection like a list ) and then iterate that collection and draw them all.
Like this:
many http://img40.imageshack.us/img40/8125/capturadepantalla201001nd.png
I took your code, and changed it, to reflect what I'm saying. The final result, uses the same component, but this component in turn draws all the rectangles.
Notice also the naming/brace style, while is not mandatory it is common while programming in Java
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
class Ramka extends JFrame {
public static final int SZEROKOSC = 800;
public static final int WYSOKOSC = 600;
Container powZawartosci = getContentPane();
DrawRectangle rectangle = new DrawRectangle();
public Ramka() {
setSize(SZEROKOSC, WYSOKOSC);
setTitle("Siatka bryły by Paweł Mysior");
powZawartosci.add( new JLabel("Several rectangles are being displayed"), BorderLayout.NORTH );
powZawartosci.add(rectangle);
}
public void addRectangle(int startX, int startY, int sizeX) {
this.rectangle.addRectangle( startY, startY, sizeX );
}
}
class DrawRectangle extends JPanel {
private java.util.List<Rectangle2D> squares;
//private int a, startX, startY;
public DrawRectangle(){
squares = new ArrayList<Rectangle2D>();
}
public void addRectangle(int startX, int startY, int a) { // square
squares.add( new Rectangle2D.Double(startX, startY, a, a) ) ;
//this.a = a;
//this.startX = startX;
//this.startY = startY;
}
public void paintComponent(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
for( Rectangle2D rect : squares ) {
g1.draw(rect);
}
}
}
public class Main {
public static void main(String[] args) {
Ramka ramka = new Ramka();
//ramka.addRectangle(200, 200, 50);
//ramka.addRectangle(100, 100, 100);
//ramka.addRectangle(300, 300, 150);
for( int i = 0 ; i < 20 ; i++ ){
ramka.addRectangle( i * 10 , i * 10 , i * 20 );
}
ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ramka.setVisible(true);
}
}

Categories