I have to create a simple 2D animation without using various primitives for drawing line, circle etc for the purpose. It has to be done by manipulating pixels and implementing one of the algorithms for drawing line, circle etc by coloring pixels.
I thought of using Turbo C for the purpose, but I use ubuntu. So I tried using dosbox to install and run turbo C but to no avail.
Now my only option is Java. Is it possible to manipulate pixels in Java? I couldn't find myself any good tutorials for the same. It would be great if a sample code for the same can be given.
The class java.awt.BufferedImage has a method setRGB(int x, int y, int rgb) which sets the color of an individual pixel. Additionally, you might want to look at java.awt.Color, especially its getRGB() method, which can convert Colors into integers that you can put into the int rgb parameter of setRGB.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DirectDrawDemo extends JPanel {
private BufferedImage canvas;
public DirectDrawDemo(int width, int height) {
canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
fillCanvas(Color.BLUE);
drawRect(Color.RED, 0, 0, width/2, height/2);
}
public Dimension getPreferredSize() {
return new Dimension(canvas.getWidth(), canvas.getHeight());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(canvas, null, null);
}
public void fillCanvas(Color c) {
int color = c.getRGB();
for (int x = 0; x < canvas.getWidth(); x++) {
for (int y = 0; y < canvas.getHeight(); y++) {
canvas.setRGB(x, y, color);
}
}
repaint();
}
public void drawLine(Color c, int x1, int y1, int x2, int y2) {
// Implement line drawing
repaint();
}
public void drawRect(Color c, int x1, int y1, int width, int height) {
int color = c.getRGB();
// Implement rectangle drawing
for (int x = x1; x < x1 + width; x++) {
for (int y = y1; y < y1 + height; y++) {
canvas.setRGB(x, y, color);
}
}
repaint();
}
public void drawOval(Color c, int x1, int y1, int width, int height) {
// Implement oval drawing
repaint();
}
public static void main(String[] args) {
int width = 640;
int height = 480;
JFrame frame = new JFrame("Direct draw demo");
DirectDrawDemo panel = new DirectDrawDemo(width, height);
frame.add(panel);
frame.pack();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
alt text http://grab.by/grabs/39416148962d1da3de12bc0d95745341.png
Another bit of fun I had today where I used #Jave Cavas, Color, Graphics and #Swing JFrame to create a simply colouring pixels class all we are doing is creating square a JFrame 400×400 pixels (few extra pixels required for the frame it self) and then we extend the Canvas and colour the pixels symmetrically.
package gcclinux.co.uk;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class ColouringPixels extends Canvas {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 407; // Additional pixels needed for the frame
private static final int HEIGHT = 427; // Additional pixels needed for the frame
#Override
public void paint(Graphics g) {
super.paint(g);
for (int r = 0; r <= 2; r++) {
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
if (x >= 1 && x <= 100 && y >= 1 && y <=100){
g.setColor(Color.WHITE);
} else if (x >= 101 && x <= 200 && y >= 101 && y <=200){
g.setColor(Color.RED);
} else if (x >= 201 && x <= 300 && y >= 201 && y <=300){
g.setColor(Color.WHITE);
} else if (x >= 301 && x <= 399 && y >= 301 && y <=400){
g.setColor(Color.RED);
} else
{
g.setColor(Color.BLUE);
}
g.drawLine(x, y, x, y);
}
}
for(int x = 0; x < HEIGHT; x++) {
for(int y = 0; y < WIDTH; y++) {
if (x >= 1 && x <= 100 && y >= 1 && y <=100){
g.setColor(Color.RED);
} else if (x >= 101 && x <= 200 && y >= 101 && y <=200){
g.setColor(Color.WHITE);
} else if (x >= 201 && x <= 300 && y >= 201 && y <=300){
g.setColor(Color.RED);
} else if (x >= 301 && x <= 399 && y >= 301 && y <=400){
g.setColor(Color.WHITE);
} else
{
g.setColor(Color.BLUE);
}
g.drawLine(x, y, x, y);
}
}
}
try {
Thread.sleep(2000); // Sleep for 2 seconds
System.exit(0); // Closed the program
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("ColouringPixels - Lesson 9");
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.add(new ColouringPixels());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
You can accomplish this using java's builtin 2D Graphics package.
Related
I am drawing a grid on a JPanel by overriding paint(g) and with it marking some points whichever clicked on the grid, but the main problem is, if someone minimize the grid or drag it around the screen, the part of the screen goes blank. I can't figure out how to change my code to have it refreshed every time the screen is minimized or dragged around, please help me with the code.
Here is my code:-
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class draw extends JPanel {
private int x,y,X,Y,xmin,xmax,ymin,ymax;
private int clickParam = 0;
private double d, theta;
private ArrayList<Integer> ab = new ArrayList<Integer>();
private ArrayList<Integer> or = new ArrayList<Integer>();
private ArrayList<Double> distance = new ArrayList<Double>();
private ArrayList<Double> angle = new ArrayList<Double>();
Graphics2D g2d = null;
public void drawing(){
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2d = g2;
int stroke[]={1,2,3,4,5};
g2.setStroke(new BasicStroke(stroke[1]));
xmin = 150;
ymin = 150;
xmax = 650;
ymax = 650;
int xsize = xmax - xmin;
int ysize = ymax - ymin;
g2.drawRect(xmin, ymin, xsize, ysize);
for(int i=50;i<=xsize;i+=50){
g2.drawLine(xmin+i, ymin, xmin+i, ymax);
g2.drawLine(xmin, ymin+i, xmax, ymin+i);
}
g2.setStroke(new BasicStroke(stroke[0]));
for(int i=10;i<=xsize;i+=10){
g2.drawLine(xmin+i, ymin, xmin+i, ymax);
g2.drawLine(xmin, ymin+i, xmax, ymin+i);
}
}
public void drawPoints(Graphics2D g2){
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax)
g2.fillOval(x-3, y-3, 7, 7);
}
public void onClick(){
addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e){
setxy(e);
setXY();
clickParam = 2;
drawPoints(g2d);
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax){
setDistance();
setAngle();
display();
}
}
});
}
public void setxy(MouseEvent e){
x = e.getX();
y = e.getY();
if(x >= xmin && x <= xmax && y >= ymin && y <= ymax){
ab.add(x);
or.add(y);
}
}
public void setXY(){
X = x - xmin;
Y = ymax - y;
}
public void setDistance(){
d = Math.sqrt(Math.pow(X/10, 2) + Math.pow(Y/10, 2));
distance.add(d);
}
public void setAngle(){
theta = Math.atan2(Y,X)*180/Math.PI;
angle.add(theta);
}
public void display(){
System.out.println("(X,Y) = ("+(X/10)+","+(Y/10)+")"+" & (d,theta) = ("+d+","+theta+")");
}
}
and the main class:-
import java.awt.Dimension;
import javax.swing.*;
public class mainClass {
public static void main(String args[]){
JFrame jframe = new JFrame("TEST");
draw d = new draw();
jframe.setPreferredSize(new Dimension(1000,1000));
jframe.pack();
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.add(d);
jframe.setVisible(true);
jframe.setResizable(false);
d.drawing();
d.onClick();
}
}
onClick is never called, therefore the MouseListener is never added.
Create a list of Points and loop through it in your paintComponent method.
drawPoints should only be called inside the paintComponent method, since it takes the current Graphics2D object.
Restructured code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class Draw extends JPanel { // Class names should start with an uppercase letter
private int xmin, xmax, ymin, ymax;
private ArrayList<Point> points = new ArrayList<Point>(); // Create a list where all clicked points will be stored
public Draw() {
xmin = 150;
ymin = 150;
xmax = 650;
ymax = 650;
addMouseListener(new MouseAdapter() { // Add MouseListener in the constructor
#Override
public void mousePressed(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
if (point.x >= xmin && point.x <= xmax && point.y >= ymin
&& point.y <= ymax) {
points.add(point); // Add the point to the list
repaint();
}
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int stroke[] = { 1, 2, 3, 4, 5 };
g2.setStroke(new BasicStroke(stroke[1]));
int xsize = xmax - xmin;
int ysize = ymax - ymin;
g2.drawRect(xmin, ymin, xsize, ysize);
for (int i = 50; i <= xsize; i += 50) {
g2.drawLine(xmin + i, ymin, xmin + i, ymax);
g2.drawLine(xmin, ymin + i, xmax, ymin + i);
}
g2.setStroke(new BasicStroke(stroke[0]));
for (int i = 10; i <= xsize; i += 10) {
g2.drawLine(xmin + i, ymin, xmin + i, ymax);
g2.drawLine(xmin, ymin + i, xmax, ymin + i);
}
drawPoints(g2);
}
private void drawPoints(Graphics2D g2) {
for (Point point : points) { // Loop through the list of points
g2.fillOval(point.x - 3, point.y - 3, 7, 7);
}
}
public static void main(String args[]) {
JFrame jframe = new JFrame("TEST");
Draw d = new Draw();
jframe.setSize(800,800);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setContentPane(d);
jframe.setVisible(true);
}
}
I have a simple class that creates a frame with some balls in it that bounce off the sides. For some reason the balls bounce fine off of the north, west, and east sides of the frame but go slightly past the south side before bouncing off of it. I take the size of the ball into account when setting the boundaries and this works fine on the x axis but not the y.
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
public class BallBounceFrame
{
public static void main(String[] args)
{
new BallBounceFrame();
}
JFrame frame;
static int WIDTH = 500;
static int HEIGHT = 500;
public BallBounceFrame()
{
frame = new JFrame("Ball Bounce Frame");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
BallCanvas c = new BallCanvas(5);
frame.add(c, BorderLayout.CENTER);
frame.setVisible(true);
c.animate();
}
class BallCanvas extends JPanel
{
private static final long serialVersionUID = 1L;
ArrayList<Ball> balls = new ArrayList<Ball>();
public BallCanvas(int ballNum)
{
for(int i = 0; i < ballNum; i++)
{
balls.add(new Ball(20));
}
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
for(Ball b : balls)
{
b.move();
g2.fill(b);
}
}
public void animate()
{
while(true)
{
try
{
frame.repaint();
Thread.sleep(10);
}
catch(Exception e)
{
System.out.println(e);
}
}
}
}
class Ball extends Ellipse2D.Float
{
private int xVel, yVel;
private int size;
private int WIDTH = BallBounceFrame.WIDTH;
private int HEIGHT = BallBounceFrame.HEIGHT;
public Ball(int size)
{
super((int) (Math.random() * (BallBounceFrame.WIDTH - 20) + 1), (int) (Math.random() * (BallBounceFrame.HEIGHT - 20) + 1), size, size);
this.size = size;
this.xVel = (int) (Math.random() * 5 + 1);
this.yVel = (int) (Math.random() * 5 + 1);
}
public void move()
{
if(super.x < 0 || super.x > WIDTH - size) xVel *= -1;
if(super.y < 0 || super.y > HEIGHT - size ) yVel *= -1;
super.x += xVel;
super.y += yVel;
}
}
}
The problem is that WIDTH and HEIGHT are from the JFrame. Especially the window title caption decreases the panel's height. One could pass the panel boundary/size to the ball's move.
#Override
public void paint(Graphics g)
{
...
b.move(getSize());
...
}
public void move(Dimension panelSize)
{
if (x < 0 || x > panelSize.getWidth() - size) xVel *= -1;
if (y < 0 || y > panelSize.getHeight - size) yVel *= -1;
x += xVel;
y += yVel;
}
To keep the ball inside the bounds you might consider:
public void move(Dimension panelSize)
{
x += xVel;
y += yVel;
if (x < 0) {
x *= -1;
xVel *= -1;
} else if (x > panelSize.getWidth() - size) {
x -= 2 * (x - panelSize.getWidth() - size);
xVel *= -1;
}
if (y < 0) {
y *= -1;
yVel *= -1;
} else if (y > panelSize.getHeight() - size) {
y -= 2 * (y - panelSize.getHeight() - size);
yVel *= -1;
}
}
According to
\ | (xVel == 5)
\|
/|\
/ | \
/ | \
(One normally also calla pack() at the end of the BallBounceFrame to do the layout calculation.)
I think, the reason is the xVel/yVel adding in move.
When you get near the border, you check if you already passed over the border. If not, you add the velocity.
If the distance to the border is 10 and your velocity is 15, you will move 5 over the boundary frame. On the next move you will reverse velocity and bounce off. The move should possibly be split in this case. move 10, reverse velocity, move 5.
This question already has answers here:
How to color a pixel?
(4 answers)
Closed 3 years ago.
On my study I have graphics lessons. We have Bresenham for line drawing and Circle drawing. On next lesson I will be learning flood fill. For flood fill I need to get pixel color to check whether I need to fill or not to fill.
This is my code now from all lessons.
package lab1;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Lab1 extends JPanel{
private Random random = new Random();
private boolean isRed;
private String s = "";
private int Fill(int x,int y,Graphics g)
{
if ((x < 0) || (y < 0) || (x >= 600) || (y >= 600)) return 0;
return 0;
}
private void drawCircle(int centerX,int centerY,int radius, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int d = (5 - radius * 4)/4;
int x = 0;
int y = radius;
Color circleColor = Color.white;
do {
g2d.drawRect(centerX + x, centerY + y, 1,1);
g2d.drawRect(centerX + x, centerY - y, 1,1);
g2d.drawRect(centerX - x, centerY + y, 1,1);
g2d.drawRect(centerX - x, centerY - y, 1,1);
g2d.drawRect(centerX + y, centerY + x, 1,1);
g2d.drawRect(centerX + y, centerY - x, 1,1);
g2d.drawRect(centerX - y, centerY + x,1,1);
g2d.drawRect(centerX - y, centerY - x, 1,1);
if (d < 0) {
d += 2 * x + 1;
} else {
d += 2 * (x - y) + 1;
y--;
}
x++;
} while (x <= y);
}
public void line(int x,int y,int x2, int y2, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
//super.paintComponent(g);
int w = x2 - x ;
int h = y2 - y ;
int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0 ;
if (w<0) dx1 = -1 ; else if (w>0) dx1 = 1 ;
if (h<0) dy1 = -1 ; else if (h>0) dy1 = 1 ;
if (w<0) dx2 = -1 ; else if (w>0) dx2 = 1 ;
int longest = Math.abs(w) ;
int shortest = Math.abs(h) ;
if (!(longest>shortest)) {
longest = Math.abs(h) ;
shortest = Math.abs(w) ;
if (h<0) dy2 = -1 ; else if (h>0) dy2 = 1 ;
dx2 = 0 ;
}
int numerator = longest >> 1 ;
for (int i=0;i<=longest;i++) {
g2d.drawRect(x, y, 1, 1);
numerator += shortest ;
if (!(numerator<longest)) {
numerator -= longest ;
x += dx1 ;
y += dy1 ;
} else {
x += dx2 ;
y += dy2 ;
}
}
}
public Lab1() {
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
drawCircle(100,500,50,g);
drawCircle(500,500,50,g);
g.setColor(Color.red);
line(50,450,550,450,g);
line(50,450,50,350,g);
line(50,350,150,350,g);
line(150,350,325,175,g);
line(325,175,400,175,g);
line(400,175,400,325,g);
line(400,325,550,325,g);
line(550,325,550,450,g);
}
//main method: create an instance of TestPanel and output it on a JFrame
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(600, 600);
f.setTitle("Sometimes Red, Sometimes Blue");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Lab1());
f.setVisible(true);
}
}
How to get pixel color from x and y ?
You can not read pixels from a Graphics object. Graphics is an abstraction for drawing, there might not be pixels (think of printing, plotting etc.).
You can create a java.awt.BufferedImage and use its createGraphics() method to get a Graphics to render into, while being able to read pixels using BufferedImage's getRGB() method to access pixels.
I would suggest to fill into a BufferedImage. There you can get the RGB value of each pixel with BufferedImage.getRGB
I am trying to find out why I get "Coordinate out of bounds!" when trying to implement the flood fill. It's a black and white image, when there is white nothing should happen when flood filling, and it doesn't so that is good. All black areas is gonna be flood filled with red and some areas become red until I get the error message that the coordinates are out of bounds. Here is the source code:
public class FloodFiller extends JPanel implements MouseListener {
private BufferedImage img;
public void turnBlacknWhite() {
int x, y;
int w = img.getWidth();
int h = img.getHeight();
// first compute the mean intensity
int totintensity = 0;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int rgb = img.getRGB(x, y);
totintensity += (rgb >> 16) & 0xFF + (rgb >> 8) & 0xFF + rgb
& 0xFF;
}
}
int meanintensity = totintensity / (w * h);
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
int rgb = img.getRGB(x, y);
int intensity = (rgb >> 16) & 0xFF + (rgb >> 8) & 0xFF + rgb
& 0xFF;
if (intensity < meanintensity) { // it's darker than mean
// intensity
img.setRGB(x, y, 0); // turn black
} else { // it's lighter
img.setRGB(x, y, 0xFFFFFF); // turn white
}
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
floodFill(e.getX(), e.getY(), 0xFF0000);
this.repaint();
}
/**
* Fill the black area including and around (x,y) with color. If (x,y) is
* not black, do nothing.
*/
public void floodFill(int x, int y, int color) {
// TODO!
int rgb = img.getRGB(x, y);
int black = Color.black.getRGB();
if (rgb == black) {
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y + 1, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y - 1, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x + 1, y, color);
}
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x - 1, y, color);
}
}
}
// public void isValid (int width, int height) {
// int coordinate = 0;
// int width = img.getWidth();
// int height = img.getHeight();
// if (width && height => coordinate) {
//
// }
// }
public FloodFiller(String fileName) {
URL imgUrl = getClass().getClassLoader().getResource(fileName);
if (imgUrl == null) {
System.err.println("Couldn't find file: " + fileName);
} else {
try {
img = ImageIO.read(imgUrl);
} catch (IOException ex) {
ex.printStackTrace();
}
}
turnBlacknWhite();
setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
this.addMouseListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
g.drawImage(img, 0, 0, null);
}
public static void main(String[] args) {
final String fileName = args[0];
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Flood Filler");
frame.setContentPane(new FloodFiller(fileName));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
Anyone who might know why this happens? :) Thanks!
The bounds on the parameters to the calls to floodFill() are not properly checked.
Look at these lines:
if (x < img.getWidth() && y < img.getHeight() && x > 0 && y > 0) {
img.setRGB(x, y, color);
floodFill(x, y + 1, color);
}
Say your image is 100 pixels tall and wide. The pixels are numbered 0-99 on each axis. Say floodfill() was just called with x = 30, y = 99. The if statement checks out, so you get to the next two lines, and now you are calling floodFill(30, 100, [color]). That call will try to run the first line in floodFill() as int rgb = img.getRGB(30, 100), and now y is out of bounds because your y-pixels only go up to 99.
Similar things happen on other image edges in the rest of floodFill().
Ive been programming a game just to become better at java. I had been having alot of trouble with getting the player rotation to work correctly. My first method used this
g2.setTransform(AffineTransform.getRotateInstance(radAngle,x_pos + (img.getWidth() / 2),y_pos+(img.getHeight() / 2)));
However this caused all images to rotate with the player thus making shooting and aiming completely disfunctional.
i was researching and saw someone use this code to make they're player rotate.
Graphics2D g2 = (Graphics2D)g;
AffineTransform oldTransform = g2.getTransform();
AffineTransform newOne = (AffineTransform)(oldTransform.clone());
newOne.rotate(radAngle,x_pos + (img.getWidth() / 2),y_pos+ (img.getHeight() / 2));
g2.setTransform(newOne);
g2.drawImage(img, x_pos,y_pos,this);
repaint();
g2.setTransform(oldTransform);
This works great and i dont have the same problems i had before. However i dont know why.
Heres my full code. The code above is for the body of the paint method.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.lang.Math.*;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.imageio.ImageIO;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
public class Game extends Applet implements Runnable, KeyListener, MouseMotionListener, MouseListener
{
//pos variables keep track of the current position of the player
int x_pos = 250;
int y_pos = 250;
//speed variables keep track of the speed/how many pixels will be added to position during this iteration of the thread
float x_speed = 0;
float y_speed = 0;
int radius = 25;
//denotes the boundries of the applet
int appletsize_x = 800;
int appletsize_y = 600;
//the x and y variables mark whether a movement key is being pressed thats telling the object to move on
//on of those axes's
int x = 0;
int y = 0;
//variables that will indicate whether one of those keys are being depressed
int up = 0;
int down= 0;
int left = 0;
int right= 0;
int mouse_x;
int mouse_y;
int tracking_angle;
//getting some images.
private BufferedImage dbImage;
private BufferedImage test;
private Graphics dbg;
private Image curser;
BufferedImage img = null;
BufferedImage round = null;
double x_dist;
double y_dist;
//i dont use this AffineTransform, although ill leave it here just incase i decide to use it if i continue working
//on this independently.
AffineTransform at = new AffineTransform();
//the angle of the mouse to the player object.
double radAngle;
public void init()
{
try {
URL url = new URL(getCodeBase(), "UFO.png");
img = ImageIO.read(url);
} catch (IOException e) {System.out.println("Cant find player image");
}
try {
URL url = new URL(getCodeBase(), "round.png");
round = ImageIO.read(url);}
catch (IOException e) {System.out.println("round not loading");}
setBackground (Color.black);
setFocusable(true);
addKeyListener( this );
curser = getImage(getDocumentBase(), "mouse.png");
addMouseMotionListener(this);
addMouseListener(this);
try
//changing the curser to the crosshair image
{
Toolkit tk = Toolkit.getDefaultToolkit();
Cursor c = tk.createCustomCursor( curser,new Point( 5, 5 ), "Cross_Hair" );
setCursor( c );
}
catch( IndexOutOfBoundsException x )
{System.out.println("Cross_hair");}
}
public class Shot {
final double angle = radAngle;
double x_loc;
double y_loc;
double X;
double Y;
public Shot(){
x_loc += x_pos;
y_loc += y_pos;
X=Math.cos(radAngle)*5;
Y=Math.sin(radAngle)*5;
}
public void move(){
x_loc += X;
y_loc += Y;}
}
//start the thread
public void start ()
{
Thread th = new Thread (this);
th.start ();
}
public void stop()
{
}
public void destroy()
{
}
//cathces the mouseEvent when the mosue is moved.
public void mouseClicked(MouseEvent e){}
public void mousePressed(MouseEvent e){
Shot shoot = new Shot();
shots.add(shoot);}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseMoved(MouseEvent e){
//get position of mouse
mouse_x = e.getX();
mouse_y = e.getY();
//get the distence from the player to the
//i calculate the actual angle of the mosue from the player object in radians
//this exists more just for debugging purposes since radians make no sense to me
tracking_angle = 90;
}
public void mouseDragged(MouseEvent e){
mouse_x = e.getX();
mouse_y = e.getY();
Shot shoot = new Shot();
shots.add(shoot);}
//this method sets the key variables to zero when the keys are released
public void keyReleased(KeyEvent r)
{
//Right
if (r.getKeyCode() == 68 ){
x = 0;
left = 0;
}
//Left
if (r.getKeyCode() == 65){
x = 0;
right = 0;
}
//Up
if (r.getKeyCode() == 87 ) {
//y_speed = 0;
down = 0;}
//Down
if (r.getKeyCode() == 83 ) {
//y_speed = 0;
up = 0;}
//move();
}
public void keyTyped(KeyEvent t){}
//changes the variables when a key is pressed so that the player object will move
public void keyPressed(KeyEvent r){
//right
if (r.getKeyCode() == 68 ){
left = 1;
}
//left
if (r.getKeyCode() == 65){
right = 1;}
//Down
if (r.getKeyCode() == 87 ) {
down = 1;}
//Up
if (r.getKeyCode() == 83) {
up = 1;}
//move();
}
//sorta like the body of the thread i think
public void run ()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true)
{
System.out.println(Math.tan(radAngle)/1);
x_dist = mouse_x - x_pos;
y_dist = mouse_y - y_pos;
radAngle = Math.atan2(y_dist , x_dist);
//if(tracking_angle < 0){
//tracking_angle = absT
if (left == 1 && x_speed < 11){
x = 0;
x_speed += 1;
}
//Right
if (right == 1 && x_speed > -11){
x = 0;
x_speed -= 1;
}
//Down
if (down == 1 && y_speed > -11) {
y_speed -= 1;}
//Up
if (up == 1 && y_speed < 11) {
y_speed += 1;}
if( x == 0 && x_speed > 0){
x_speed -=.2;}
if( x == 0 && x_speed < 0){
x_speed +=.2;}
if( y == 0 && y_speed > 0){
y_speed -=.2;}
if( y == 0 && y_speed < 0){
y_speed +=.2;}
if (x_pos > appletsize_x - radius && x_speed > 0)
{
x_pos = radius;
}
else if (x_pos < radius && x_speed < 0)
{
x_pos = appletsize_x + radius ;
}
if (y_pos > appletsize_y - radius && y_speed > 0){
y_speed = 0;}
else if ( y_pos < radius && y_speed < 0 ){
y_speed = 0;}
x_pos += (int)x_speed;
y_pos += (int)y_speed;
repaint();
try
{
//tells the thread to wait 15 milliseconds util it executes again.
Thread.sleep (15);
}
catch (InterruptedException ex)
{
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
}
public void update (Graphics g)
{
if (dbImage == null)
{
dbImage = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_RGB);
dbg = dbImage.getGraphics ();
}
dbg.setColor (getBackground ());
dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);
dbg.setColor (getForeground());
paint (dbg);
shot_draw(dbg);
g.drawImage (dbImage, 0, 0, this);
}
ArrayList<Shot> shots = new ArrayList<Shot>();
double last_angle = 1000;
public void paint (Graphics g){
Graphics2D g2 = (Graphics2D)g;
AffineTransform oldTransform = g2.getTransform();
AffineTransform newOne = (AffineTransform)(oldTransform.clone());
newOne.rotate(radAngle,x_pos + (img.getWidth() / 2),y_pos+(img.getHeight() / 2));
g2.setTransform(newOne);
g2.drawImage(img, x_pos,y_pos,this);
repaint();
g2.setTransform(oldTransform);
// g2.setTransform(AffineTransform.getRotateInstance(radAngle,x_pos + (img.getWidth() / 2),y_pos+(img.getHeight() / 2)));
//g2.getTransform().setToIdentity();
}
public void shot_draw(Graphics g){
Graphics2D g2 = (Graphics2D)g;
// Shot shoot = new Shot();
// shots.add(shoot);
for(Shot i: shots){
g2.drawImage(round,(int)i.x_loc+40,(int)i.y_loc+40,this);
i.move();}
}}
Here are the images I'm using:
This makes sense since if you don't reset the Graphics object's AffineTransform back to its baseline, it will use the new transform to draw everything including all images. I don't understand however why you have a call to repaint() from within your paint method. You shouldn't do this.
The AffineTransform object is connected to the Graphics2D object via the call to setTransform. Once connected, the transform causes every object drawn using the Graphics2D object to be drawn with that same transform (in this case, rotation) applied to it until a new AffineTransform is assigned to the Graphics2D object via another call to setTransform. The sample code you found saved the old transform (which presumably encodes a normal, non-rotated state) via
AffineTransform oldTransform = g2.getTransform();
The code then created the rotation transform and connected it to the Graphics2D (now all objects drawn would be rotated until a new transform be assigned), then drew the one object that needed to be drawn rotated (which therefore had the newly-created rotation transform applied to it), and then restored the original, non-rotating transform to the Graphics2D object via:
g2.setTransform(oldTransform);
That way, the transform that would be applied to subsequent objects would be the original, non-rotating transform.