I would like to have a loop that will run through each of the images i have. I would like to draw them to the screen and it works fine if i draw each image separately but it uses a lot of code. Whilst using a loop to paint each image should uuse a lot less code. This is my code.
String image[] = {"carA", "carB"};
for(int i = 0; i < image.length; i++){
g.drawImage(image[i].getImage(), image[i].getX(), image[i].getY(),
image[i].getWidth(), image[i].getHeight(), this);
}
It says the problem is that strings are being used. The getX() and getY() etc finds out the x and y coordinates.
How can I get this to work?
You are trying to call getImage /getX / getY on the String object.
You should load your Image first into the Image object like that
Image img1 = Toolkit.getDefaultToolkit().getImage(image[i]);
Use the drawString() method, it can draw strings:
You should initialize all data about images, try this example:
String imageDatas[][] = {
{"image_path_1.jpg", "0", "0", "100", "100"},
{"image_path_2.jpg", "100", "0", "100", "100"}
};
for (String[] imageData : imageDatas) {
String filePath = imageData[0];
int x = Integer.parseInt(imageData[1]);
int y = Integer.parseInt(imageData[2]);
int width = Integer.parseInt(imageData[3]);
int height = Integer.parseInt(imageData[4]);
Image img = Toolkit.getDefaultToolkit().getImage(filePath);
g.drawImage(img, x, y, width, height, this);
}
String is a type that store characters. So it can not be used for your requirements.
To meet the requirements you should crate own type.
Good place to start i to create a interface that your class will be using.
public interface IMichaelImage {
int getX();
int getY();
Image getImage();
}
Then you need to create a class that will be able to store the information that you program logic will use
public MichaelImage implements IMichaelImage {
private int x = 0;
private int y = 0;
private Image image;
public MichaelImage(Image image) {
this.image = image;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
#Override
public int getX() {
return this.x;
]
#Override
public int getY() {
return this.x;
}
public Image getImage() {
return this.image;
}
}
On the and you will have something like this
Collection<IMichaelImage> images = loadImages();
for(IMichaelImage image : images) {
g.drawImage(image.getImage(), image.getX(), image.getY());
}
Related
I'm trying to create an external Archer class for a tower defense game with its own draw function, but I'm having trouble accessing the image function from within the Archer class. I've got a workaround working as shown below but I feel like there must be a better way to do it.
public class Sketch extends PApplet {
static PImage archerImg;
static Sketch s;
public void setup() {
s = this;
archerImg = loadImage("img/Archerv2.png");
}
}
class Archer {
public Archer(int x, int y) {
this.x = x;
this.y = y;
image = Sketch.archerImg;
}
public void draw() {
Sketch.s.image(image, x, y);
}
}
Can anyone recommend a more elegant way to do this?
As far as I understand you're trying to get a reference to the sketch so you can simply use image() when rendering an instance of Archer from the scope of the class itself.
One option could to take advantage of the fact that g is PApplet's global PGraphics buffer which provides the rendering functions (such image()):
public class Sketch extends PApplet {
PImage archerImg;
Archer archer;
public void setup() {
size(300, 300);
archerImg = loadImage("img/Archerv2.png");
archer = new Archer(150, 150, archerImg);
}
public void draw(){
background(0);
archer.draw(g);
}
public void mouseDragged(){
archer.x = mouseX;
archer.y = mouseY;
}
}
class Archer {
int x, y;
PImage image;
public Archer(int x, int y, PImage image) {
this.x = x;
this.y = y;
this.image = image;
}
public void draw(PGraphics g) {
g.image(image, x, y);
}
}
The advantage is that if you chose to have multiple buffers(e.g. a background layer, sprites layer, a HUD layer, etc.) you can explicitly tell the Archer instance into which layer it should render to.
Alternatively you can pass the sketch directly in the constructor which you can reuse later to call image:
public class Sketch extends PApplet {
PImage archerImg;
Archer archer;
public void setup() {
size(300, 300);
archerImg = loadImage("img/Archerv2.png");
archer = new Archer(this, 150, 150, archerImg);
}
public void draw(){
background(0);
archer.draw();
}
public void mouseDragged(){
archer.x = mouseX;
archer.y = mouseY;
}
}
class Archer {
int x, y;
PImage image;
PApplet parent;
public Archer(PApplet parent, int x, int y, PImage image) {
this.x = x;
this.y = y;
this.image = image;
this.parent = parent;
}
public void draw() {
parent.image(image, x, y);
}
}
If you can to pass the Sketch directly you can as well, though this would mean even tighter coupling:
public class Sketch extends PApplet {
public PImage archerImg;
Archer archer;
public void setup() {
size(300, 300);
archerImg = loadImage("img/Archerv2.png");
archer = new Archer(this, 150, 150);
}
public void draw(){
background(0);
archer.draw();
}
public void mouseDragged(){
archer.x = mouseX;
archer.y = mouseY;
}
}
class Archer {
int x, y;
Sketch parent;
public Archer(Sketch parent, int x, int y) {
this.x = x;
this.y = y;
this.parent = parent;
}
public void draw() {
parent.image(parent.archerImg, x, y);
}
}
Without more context on the design of your game it's tricky to get an exact answer, however you have multiple options above. Personally, even though it's slightly more verbose I'd go with the PGraphics option since less coupled than the other options.
One option would be to use preload() to load the image; it is run once before the rest of your code. The following will run in Processing IDE using p5.js mode. The img folder with the archer image inside needs to be in your sketch folder.
let archerImg;
function preload(){
archerImg = loadImage('img/Archerv2.png');
}
function setup() {
createCanvas(500,500);
background(209);
archer = new Archer(50,60);
}
function draw() {
archer.display();
}
class Archer {
constructor(x, y) {
this.x = x;
this.y = y;
}
display() {
image(archerImg, this.x, this.y );
}
}
i need to change the colour of a car PNG image when it crash to a block, like a kind of filter here's the 2 class
public class Sprite {
//classe estendibile a tutti gli oggetti
protected int x;
protected int y;
protected int width;
protected int height;
protected boolean visible;
protected Image image;
public Sprite(int x, int y) {
this.x = x;
this.y = y;
visible = true;
}
protected void getImageDimensions() {
width = image.getWidth(null);
height = image.getHeight(null);
}
protected void loadImage(String imageName) {
ImageIcon ii = new ImageIcon(imageName);
image = ii.getImage();
}
public Image getImage() {
return image;
public Rectangle getBounds() {
return new Rectangle(x, y, width,
height);
}
}`
public class Car extends Sprite {
public Car(int x, int y) {
super(x, y);
loadImage("src/car.png");
getImageDimensions();
}
Well I suppose it depends on the picture. If your picture looks like this
I suppose that going pixel by pixel and using image.setRGB(x, y, newColour) on pixels, that satisfy a condition of image.getRGB(x, y) == colourToChange will work. If you want to process a picture like
you would probably first need to run some recognition algorithm to find out which pixels are actually of the car and which are the background (wheels, shadows, etc.) and then run a filter over those. While this time based on the RGB of the original pixel you would need to calculate the new colour so that what was originally dark, remains dark and what was originally light remains light and so on.
I really could use some help in order to find a working solution for my game.
My game is almost done, but the walls in my game are still not working as they should.
I have tried to find a solution on the internet for this problem, but i still haven't found a simple way to stop a rectangle just before it will collide with a wall (another rectangle).
Right now i have implemented a collision detection between the player rectangle and the wall rectangle and then stopped it to move, but then it gets stuck inside a wall when it hits.
Want it to stop just before, so it still can move. The code i have done this with so far is here:
Pacman Class
public class Pacman {
private String pacmanup = "pacmanup.png";
private String pacmandown = "pacmandown.png";
private String pacmanleft = "pacmanleft.png";
private String pacmanright = "pacmanright.png";
private int dx;
private int dy;
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image imageup;
private Image imagedown;
private Image imageleft;
private Image imageright;
public Pacman() {
ImageIcon i1 = new ImageIcon(this.getClass().getResource(pacmanup));
imageup = i1.getImage();
ImageIcon i2 = new ImageIcon(this.getClass().getResource(pacmandown));
imagedown = i2.getImage();
ImageIcon i3 = new ImageIcon(this.getClass().getResource(pacmanleft));
imageleft = i3.getImage();
ImageIcon i4 = new ImageIcon(this.getClass().getResource(pacmanright));
imageright = i4.getImage();
width = imageup.getWidth(null);
height = imageup.getHeight(null);
visible = true;
x = 270;
y = 189;
}
public int getDx() {
return dx;
}
public void setDx(int dx) {
this.dx = dx;
}
public int getDy() {
return dy;
}
public void setDy(int dy) {
this.dy = dy;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public Image getImageup() {
return imageup;
}
public Image getImagedown() {
return imagedown;
}
public Image getImageleft() {
return imageleft;
}
public Image getImageright() {
return imageright;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public boolean isVisible() {
return visible;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public void move() {
x += dx;
y += dy;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -2;
dy = 0;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 2;
dy = 0;
}
if (key == KeyEvent.VK_UP) {
dx = 0;
dy = -2;
}
if (key == KeyEvent.VK_DOWN) {
dx = 0;
dy = 2;
}
}
Here i have created a Rectangle getBounds method which i use to create an rectangle of the pacman and place an image over it.
Barrier class / Wall class
public class Barrier {
private String barrier = "barrier.png";
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image image;
public Barrier(int x, int y) {
ImageIcon ii = new ImageIcon(this.getClass().getResource(barrier));
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
visible = true;
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public void setVisible(Boolean visible) {
this.visible = visible;
}
public Image getImage() {
return image;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
This class also have the Rectangle getBounds class which i use to detect collision.
The last code i show is how i do the collision detection so far:
Code inside Board class
Rectangle r3 = pacman.getBounds();
for (int j = 0; j<barriers.size(); j++) {
Barrier b = (Barrier) barriers.get(j);
Rectangle r4 = b.getBounds();
if (r3.intersects(r4)) {
System.out.println("Wall hit");
pacman.setDx(0);
pacman.setDy(0);
}
}
Well, what i do, if there is a collision between r3 and r4, i gonna set Dx and Dy to 0.. what i want to find another solution so it detect for collision but i wont get stuck inside a wall, but i don't know how to :/
Hope someone will help.
There are two approaches you can follow. One is ugly but easier, the other one requires a deeper redesign of your classes.
1) Ugly/Simple Approach
In the ugly one, you keep moving your guy before doing the collision checks. Simply move your pacman back to the point where it was not stuck. You accomplish that by inverting the last directions used:
Code inside Board class
Change your reaction in case you find a collision: just walk the same distance, backwards.
if (r3.intersects(r4)) {
System.out.println("Wall hit, move back");
pacman.setDx(-pacman.getDx());
pacman.setDy(-pacman.getDy());
// Possibly need to call move() here again.
pacman.move();
break;
}
Ugly, but should work.
Not recommended to coding perfectionists with OCD and heart disease, though.
2) Redesign
In this approach, you test the position pacman will occupy before doing any actual moves. If that spot is not into any barrier, then perform the movement for real.
Code inside Pacman class
Add this method, so that you can check for collisions against the new bounds.
public Rectangle getOffsetBounds() {
return new Rectangle(x + dx, y + dy, width, height);
}
Code inside Board class
// Strip the call to pacman.move() prior to this point.
Rectangle r3 = pacman.getOffsetBounds(); // Check against the candidate position.
for (int j = 0; j<barriers.size(); j++) {
Barrier b = (Barrier) barriers.get(j);
Rectangle r4 = b.getBounds();
if (r3.intersects(r4)) {
System.out.println("Wall hit");
pacman.setDx(0);
pacman.setDy(0);
// Quit the loop. It's pointless to check other barriers once we hit one.
break;
}
}
// Now we're good to move only in case there's no barrier on our way.
pacman.move();
Particularly I prefer this approach, but it's up to you to pick the best one.
in this class that i have extending JLabel I need to be able to use the mouse to left click, then drag down and/or right to create a rectangle and be able to repeat that process to draw multiple rectangles without losing any of the previous ones and drawing boxes for overlap as well as being able to find the rectangle made by the union of all rectangles like this
my current code was adapted as much as i could from the java demo on Performing Custom Painting the program seems to be behaving in odd ways because of how the repaint method is used to update the JLabel but i have no idea how to fix it
JLabel class
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class JLabelx extends JLabel {
private int squareX = 0;
private int squareY = 0;
private int squareW = 0;
private int squareH = 0;
public JLabelx() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
squareX = e.getX();
squareY = e.getY();
//set coordinates of next rectangle
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
newDraw(e.getX(),e.getY());
//find length and width of next rectangle
}
});
}
protected void newDraw(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
// repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareW=x-squareX;
squareH=y-squareY;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
protected void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.GREEN);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}
I have also been given a Rectangle class that looks similar to java.awt.Rectangle which has methods that find the rectangles made by overlaps and the rectangles made by the union of all rectangles, but I don't know how to create rectangle objects with mouse movements and then paint them in this JLabel
public class Rectangle {
private int x,y,width,height;
public Rectangle(int x,int y,int width,int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Rectangle(Rectangle a)
{
this.x = a.x;
this.y = a.y;
this.width = a.width;
this.height = a.height;
}
public String toString()
{
return "Start: ("+x+","+y+"), Width: "+width+", Height: "+height+"\n";
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public void setX(int x)
{
this.x = x;
}
public void setY(int y)
{
this.y = y;
}
public void setWidth(int width)
{
this.width = width;
}
public void setHeight(int height)
{
this.height = height;
}
public int area()
{
return width*height;
}
public boolean overlaps(Rectangle a)
{
if ((x>a.x+a.width) || (a.x>x+width) || (y>a.y+a.height) || (a.y>y+height))
{
return false;
}
return true;
}
public Rectangle intersect(Rectangle a)
{
if (!overlaps(a))
return null;
int left,right,top,bottom;
if (x<a.x)
left = a.x;
else
left = x;
if (y<a.y)
bottom = a.y;
else
bottom = y;
if ((x+width)<(a.x+a.width))
right = x+width;
else
right = a.x+a.width;
if ((y+height)<(a.y+a.height))
top = y+height;
else
top = a.y+a.height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
public Rectangle union(Rectangle a)
{
int left,right,top,bottom;
if (x<a.x)
left = x;
else
left = a.x;
if (y<a.y)
bottom = y;
else
bottom = a.y;
if ((x+width)<(a.x+a.width))
right = a.x+a.width;
else
right = x+width;
if ((y+height)<(a.y+a.height))
top = a.y+a.height;
else
top = y+height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
}
Not sure why you are extending a JLabel to do custom painting. The tutorial showed you how to use a JPanel.
For the two common ways to do incremental paint, check out Custom Painting Approaches:
Use a List to keep track of the Rectangles (this is probably what you want since you want to be able to test for intersections.
Use a BufferedImage.
I've run into a design problem in my java code. My application uses missiles, and there are different types of missiles that all work identical except they have 3 unique attributes. The constructor of a missile must know these attributes. I decided to make missile an abstract class, but I can't assign values to protected variables in a subclass outside of a method/constructor. Also I can't declare the variables in the constructor, because I must make the call to the super-constructor first thing.
How can I be smart about this problem?
public abstract class Missile {
private int x, y;
private Image image;
boolean visible;
private final int BOARD_WIDTH = 390;
protected final int MISSILE_SPEED;
protected final int MISSILE_HEIGHT;
protected String file;
public Missile(int x, int y) {
ImageIcon ii =
new ImageIcon(this.getClass().getResource(file));
image = ii.getImage();
visible = true;
this.x = x;
this.y = y - Math.floor(MISSILE_HEIGHT/2);
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public void move() {
x += MISSILE_SPEED;
if (x > BOARD_WIDTH)
visible = false;
}
}
And there is an ideal implementation of a subclass, except it doesn't work. (it can't recognize the protected variables). What do I do?
public class Laser extends Missile {
MISSILE_SPEED = 2;
MISSILE_HEIGHT = 5;
file = "laser.jpg";
public Laser(int x, int y) {
super(x, y);
}
}
I think the best way to do what you want it to do is make abstract methods in Missile that the subclasses have to implement. For example, add these to Missile:
public abstract int getMissileSpeed();
public abstract int getMissileHeight();
public abstract int getFileName();
Then your subclass has to implement it, and you can make it constant like so:
public class Laser extends Missile {
public Laser(int x, int y) {
super(x, y);
}
public int getMissileSpeed() {
return 2;
}
public int getMissileHeight() {
return 5;
}
public String getFileName() {
return "laser.jpg";
}
}
edit: And then of course anywhere that you want to retrieve the constant value you just call those methods.
Change the base class fields and constructors to
protected final int speed;
protected final int height;
public Missile(int x, int y, int speed, int height, String file) {
ImageIcon ii =
new ImageIcon(this.getClass().getResource(file));
image = ii.getImage();
visible = true;
this.speed = speed;
this.height = height;
this.x = x;
this.y = y - Math.floor(height/2);
}
And the subclass to:
public class Laser extends Missile {
public Laser(int x, int y) {
super(x, y, 2, 5, "laser.jpg");
}
...
}
The attributes are already in the base class, so they must not be redefined in the subclass. All-uppercase naming is reserved to constants in Java.
I'm not sure if missile needs to be an abstract class, but I think something like this might be what you're going for:
public abstract class Missile {
private int x, y;
private Image image;
boolean visible;
private final int BOARD_WIDTH = 390;
protected final int MISSILE_SPEED;
protected final int MISSILE_HEIGHT;
public Missile(int x, int y, int speed, int height, String file) {
MISSILE_SPEED = speed;
MISSILE_HEIGHT = height;
ImageIcon ii = new ImageIcon(this.getClass().getResource(file));
image = ii.getImage();
visible = true;
this.x = x;
this.y = y - Math.floor(MISSILE_HEIGHT/2);
}
}
public class Laser extends Missile {
public Laser(int x, int y) {
super(x, y, 2, 5, "laser.jpg");
}
}
Create an interface and put all your final fields in it.
Now implement this interface within Missile and Laser both. At least that would solve the issue of access.