How to rotate a square Image in Java ? - java

i am working in a game like Geometry dash on java , i got all of the mechanics like , wave , ball , ufo , ship.... anyway i am trying to achieve the effect of the square rotating when it jumps like the original game y try to do this using affineTransform but it doesnt work like the original game
i use this code to rotate , but looks weird
public void rotate(){
tx.rotate(Math.toDegrees(degrees),width/2,width/2);
op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
}
here is a capture of my game looking right now
here is a link of geometry dash were you can see how the square rotate in middle air(what i am trying to do)
got any ideas? please help me :c

hmmm, I would actually use an AffineTransform but in another way...
if you have the two functions
public void tick()
{
}
public void render(Graphics g)
{
}
I would do something like:
AffineTransform at;
rotation = 0;
public Player()
{
at = AffineTransform.getTranslateInstance(x, y);
}
public void tick()
{
at = AffineTransform.getTranslateInstance(x, y);
if(isInAir)
{
rotation++;
at.rotate(Math.toRadians(rotation), width / 2, height / 2);
}
else
{
rotation = 0;
}
}
public void render(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(sprite, at, null);
}
I know it's not that practical, always creating another AffineTransform but it worked for me. Another way to do it in the render method, not using any AffineTransform would be:
Graphics2D g2d = (Graphics2D) g;
g2d.rotate(Math.toRadians(rotation));
g.drawImage(sprite, x, y, null);
g2d.rotate(Math.toRadians(-rotation));
I'm not quite sure if you would need Math.toRadians here, but if not just delete it.
Hope I could help!

Related

How can I create a Rectangle with a blend mode using a Graphics2D object in Java?

I am attempting to create a day/night cycle in a simple RPG-style game with Java. I have reached a point where I have included a low-alpha color overlay will change hue over time to simulate this:
// Render the overlay rectangle.
public void render(Graphics2D g) {
// Set the color to yellow with ~50% opacity.
g.setColor(new Color(255, 255, 0, 125));
// Draw the rectangle.
g.fillRect(0, 0, handler.getWidth(), handler.getHeight());
g.dispose();
}
While this works, I would like to introduce blending modes (i.e. add, subtract, screen, soft light) into my code to increase the day/night cycle's realism.
Here's what I have tried, but to no avail:
Researching JavaFX's blending mode options. I don't want to switch to JavaFX.
Creating an all-white image that overlays the screen and uses setComposite() and setXORMode() from a different StackOverflow answer.
Using an image with a BlendingMode and setComposite() from the package org.jdesktop.swingx.graphics.BlendComposite.
My desired code is something similar to what follows, but I will take what I can get.
public void render(Graphics2D g) {
g.setColor(new Color(255, 255, 0, 125));
g.setBlendMode(ADD);
g.fillRect(0, 0, handler.getWidth(), handler.getHeight());
g.dispose();
}
One possibility to solve this would be to buffer your screen in a BufferedImage and then implement your own drawing methods(This definitely isn't a fast way to do this as it throws away all hardware-acceleration. If you need to render a big screen this can be laggy depending on your system and your implementation.):
class MyGraphics {
public enum BlendingMode {
NORMAL, ADD, …
}
public BufferedImage buffer;
private BlendingMode bm = BlendingMode.NORMAL;
private int color = 0;
public MyGraphics(BufferedImage buf) {
buffer = buf; // Initialize it with a bufferedImage of your panel size.
}
public void setBlendMode(BlendingMode b) {
bm = b;
}
private int applyBlendingMode(int imgColor1, int newColor) {
int rImg, rNew, gImg, gNew, bImg, bNew, alphaImg, alphaNew; // You can intialize those using bitshifts from the color integers.
switch(bm) {
// Implement all your blending modes here.
}
// And don't forget to return the result!
}
public void setColor(int c) {
color = c;
}
public void fillRect(int x0, int y0, int width, int height) {
for(int x = x0; x < x0+width; x++) {
for(int y = y0; y < y0+height; y++) {
buffer.setRGB(x, y, applyBlendingMode(buffer.getRGB(x, y), color));
}
}
}
}
If the setRGB and getRGB are working to slow for you, you might speed it up by working directly on the BufferedImage's data array(see here for further info).
Also keep in mind, that if you want to use normal blending mode, you can still do it the normal way using buffer.getGraphics() to get your Graphics object. This should be faster in most cases.
After you are done with implementing your blending-modes and maybe some further functionality to draw more then a rectangle you can just simply draw the underlying BufferedImage on your screen using Graphics.drawImage(buffer, 0, 0);

Inaccurate Graphics2D.draw(Shape) method

I make a game and when I animate entity with low velocity I use g.FILL(new Ellipse2D.Float(x, y, r, r)); because it renders smooth and fluent motion.
It work fine (in Example blue left circle). But when I needed just an outline of circle I used g.DRAW(new Ellipse2D.Float(x, y, w, h)); and it didn't work and I absolutely don't know what's wrong. No fluent motion, circle jumps pixel over pixel and it looks ugly (in Example red right circle). Graphics2D.draw(Shape) count float values like int values.
This Example code demonstrate it, don't study it a lot, just import, run and watch.
public class Example extends JFrame {
public static void main(String[] args) { new Example(); }
public Example() {
setBounds(50, 50, 400, 400);
setVisible(true);
while(true) {
x1 += 0.01;
y1 += 0.01;
x2 -= 0.01;
y2 += 0.01;
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
double x1 = 50 , y1 = 50;
double x2 = 250, y2 = 50;
#Override
public void paint(Graphics gg) {
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.BLUE);
g.fill(new Ellipse2D.Double(x1, y1, 100, 100));
g.setColor(Color.RED);
g.draw(new Ellipse2D.Double(x2, y2, 100, 100));
}
}
So how can I fix it without tricks like filling two cirle or moving image of circle? Thanks for every answer.
I would guess the problem is that you didn't invoke super.paint(...) as the first statement in the method which means you lose some of the default painting functionality.
However, that is NOT the proper solution as you should NOT be overriding the paint() method of a JFrame at all. Custom painting is done by overriding the `paintComponent(...) method of a JPanel and then you add the panel to the frame. Read the section from the Swing tutorial on Custom Painting for more information and working examples.
Also, don't use a while true loop for animation. Instead you should be using a Swing Timer to schedule the animation (the tutorial has a section on Swing Timers). Your code only works because you are NOT creating the GUI correctly. The GUI should be created on the Event Dispatch Thread. The Custom Painting tutorial shows you how to use the invokeLater(...) method to do this. The tutorial also has a section on Concurrency in Swing which explains this concept in more detail.
With drawing circles/ovals/ellipses in Java, the "pure" mode often helps drawing it with subpixel accuracy:
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE)
My other answer has more details: https://stackoverflow.com/a/31221395/1143274

Canvas buffering screen size

I wrote these code in a class which extends Canvas.
(please have a look at the pictures at these links if you don't want to read, i can't post pictures directly because of stackoverflow reputation or something)
http://tinypic.com/r/oaw3u8/5
http://tinypic.com/r/24g9ldz/5
final static int WIDTH = 800;
final static int HEIGHT = 600;
Dimension SIZE = new Dimension(WIDTH, HEIGHT);
Game() {
setPreferredSize(SIZE);
**
**
*
*
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.cyan);
Graphics2D g2 = (Graphics2D) g;
**g.fillRect(0, 0, getWidth(), getHeight());**
g.dispose();
bs.show();
}
question is about the double-stared line of code, which is used for refreshing the screen by drawing a screen-size rectangle.
**at the first time, my code was
g.fillRect(0,0,WIDTH,HEIGHT);
then i notice the balck rectangle was smaller then the screen. there was a minor,about 1 inch, margin at the right inside of the frame.(i might use "margin" wrong but i hope you get what i mean)
so i used getWidth(),getHeight() instead of using the exact variable WIDTH and HEIGHT.
and it worked well,
i don't know the reason why ?
please help me why is this happening, are variable not accurate in this situation? or what .
thank you very much

Seeing pixels of a SVG file when scaling in Java

I am handling a SVG file in Java using Batik library. The problem occurs when i scale it. I can see pixels of lines. Off course this should not happen, i should be able to zoom at least about 4000% and maintain the smoothness.
SVG file is read from an extended class, and it is painted from an override paint method. First i set new scale to AffineTransform variable, apply this to graphics of the method and paint using super.paint().
I am really stuck and can't figure out the problem. SVG files I am using are ok, I opened them in Inkscape and could zoom without the pixels showing. Please help.
code:
#Override
public void paint(Graphics g) {
try {
rad = (int)(radInit*zoom);
updateTransform();
Graphics2D g2d = (Graphics2D) g;
g2d.setTransform(transform);
super.paint(g);
paintElements(g2d);
} catch(NullPointerException nulle) {
// System.out.println("SVG not loaded yet");
}
}
private void updateTransform(){
transform = new AffineTransform();
transform.translate((-1)*zoom*centarX, (-1)*zoom*centarY);
transform.scale(zoom, zoom);
}
What was needed was
this.setRenderingTransform(transform, true);
This way no pixels can be seen or rather, everything is painted as it should be.

can't get my coordinates graphics2D mouseclick java

I got an extended JLabel class where I draw my Map using the code below :
the new AffineTransform() is the identity to left my image as it is (0,0,w,h)
mygraphics2D = (Graphics2D) getGraphics();
graphics2D.scale(2.0,2.0) ;
graphics2D.rotate(....
graphics2D.drawImage(myImageIcon.getImage(),new AffineTransform(), this);
now when I click on my JLabel using this event :
public void mouseClicked(MouseEvent e) {
x =e.getX() ;
y = e.getY();
NewX = ????
NewY = ????
}
I want to retrieve my new coordinates "the scaled,rotated ... coords" I tried
Point2D ptSrc = new Point2D.Double(x, y);
Point2D ptDst = new Point2D.Double(0, 0);
mygraphics2D.getTransform().transform(ptSrc, ptDst);
but the ptDst is different from the (scaled,rotated,..) coordinates, any help please !!!
It sounds like you need both a forward and inverse transform to translate between the two co-ordinate systems. In this example, the scaling equations are explicit; in this alternate approach, a second AffineTransform is used.
Its not so hard ;-)
When you repaint the Component save the AffineTransform after the transforming with g2.getTransform()
Then call the function invert() on it
In the mouseClicked() event us the following code:
Point2D p= trans.transform(new Point2D.Double(evt.getX(), evt.getY()), null);
System.out.println("click x="+p.getX()+" y="+p.getY());
Thats it!
I found these:
http://www.javalobby.org/java/forums/t19387.html
http://www.java.net/node/685054
Don't know if they will help or not.

Categories