I have a platformer class that creates a window and spawns platforms and a "character". It uses another class platform to make platforms. The character is supposed to jump up and land on the platforms. I use the getBounds and getTopY functions for collision detection but they only work for the first platform. How can i get them to work for multiple platforms?
public class Platformer extends JPanel {
Platform platform = new Platform(this);
Character character = new Character(this);
public Platformer() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
character.keyTyped(e);
}
#Override
public void keyReleased(KeyEvent e) {
character.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
character.keyPressed(e);
}
});
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
platform.Location(150,200);
platform.paint(g2d);
platform.Location(200,120);
platform.paint(g2d);
character.paint(g2d);
}
private void move(){
character.move();
}
public static void main(String args[]){
JFrame frame = new JFrame("Mini Tennis");
//create new game
Platformer platformer = new Platformer();
//add game
frame.add(platformer);
//size
frame.setSize(400, 400);
frame.setVisible(true);
//set close condition
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
platformer.move();
platformer.repaint();
try {
Thread.sleep(10);//sleep for 10 sec
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
public class Platform {
private static final int Height = 10;
private static final int Width = 60;
int x;
int Y;
private Platformer platformer;
public Platform(Platformer platformer) {
this.platformer = platformer;
}
public void Location(int xin, int yin) {
x = xin;
Y = yin;
}
public void paint(Graphics2D g) {
g.fillRect(x, Y, Width, Height);
}
public Rectangle getBounds() {
return new Rectangle(x, Y, Width, Height);
}
public int getTopPlat() {
return Y;
}
}
Actually you have only one platform. And you draw this platform twice in different places (paint function in Platformer):
platform.Location(150,200);
platform.paint(g2d);
platform.Location(200,120);
platform.paint(g2d);
Therefore I suppose you handle only one platform (with coordinates 200 and 120). You must keep all of your platforms and handle each of them separately.
Related
QUESTION
I'm trying to create a simple object "car" animation in Processing.
My code is:
Car car;
void setup(){
size(800, 600);
background(#818B95);
frameRate(30);
car = new Car(10,10);
}
void draw(){
//refresh background
background(#818B95);
print("-");
car.drawCar();
}
void mouseClicked() {
car.run();
}
public class Car implements Runnable{
private int pos_x, pos_y;
public Car(int pos_x, int pos_y){
this.pos_x = pos_x;
this.pos_y = pos_y;
}
public void drawCar(){
rect(pos_x,pos_y,10,10);
}
public void run(){
while(true){
pos_x += 10;
print("*");
delay(200);
}
}
}
I'm expecting to see the car/rectangle move right when I click the mouse button, but nothing happens.
I've added the two print in order to see if the draw method and my car.run are executed in parallel showing some * and - printed alternately.
What I see is a sequence of - until I click and then only * are printed.
Is it possible that starting a new object thread will stop the main draw cycle?
SOLUTION
This is just a variant of the suggested solution (by Mady Daby) without using threads.
Car car;
void setup(){
size(800, 600);
background(#818B95);
frameRate(30);
car = new Car(10,10);
}
void draw(){
//refresh background
background(#818B95);
print("-");
car.drawCar();
}
void mouseClicked() {
car.moving = true;
}
public class Car{
private int pos_x, pos_y;
boolean moving = false;
public Car(int pos_x, int pos_y){
this.pos_x = pos_x;
this.pos_y = pos_y;
}
public void drawCar(){
rect(pos_x,pos_y,10,10);
//animation
if(moving){
pos_x += 10;
print("*");
}
}
}
You could make the car move right by just introducing a boolean variable to track whether the car is supposed to be moving right moving and then increment pos_x if moving is true. You can also use the clicks to toggle between moving and not moving.
Car car;
void setup() {
size(800, 600);
background(#818B95);
frameRate(30);
car = new Car(10, 10);
}
void draw() {
//refresh background
background(#818B95);
print("-");
car.drawCar();
}
void mouseClicked() {
car.toggleMoving();
}
public class Car implements Runnable {
private int pos_x, pos_y;
private boolean moving = false;
public Car(int pos_x, int pos_y) {
this.pos_x = pos_x;
this.pos_y = pos_y;
}
public void toggleMoving() {
moving = !moving;
}
public void drawCar() {
if (moving) {
this.run();
}
rect(pos_x, pos_y, 10, 10);
}
public void run() {
pos_x += 10;
print("*");
delay(200);
}
}
For a few days I have been trying to create a JPanel, that comes flying in from the side. I found the Universal Tween Engine and also saw a few demos but for some reason I was never able to make it work in my own code. For the sake of simplicity let's just attempt to move a JPanel (containing an image in a JLabel) from (0,0) to (600,0) on a JFrame. This is what I've got so far and the closest I have ever gotten to actually moving things with this framework, all it does it make the JPanel jump to its destination within the first tick or so. It is supposed to be so simple but I must be missing something...
SlideTest.java - Creating the UI, initializing the Thread + Tween
public class SlideTest {
TweeningPane p;
public TweenManager tweenManager;
public static void main(String[] args) {
new SlideTest();
}
public SlideTest() {
try {
setupGUI();
} catch (IOException e) {
e.printStackTrace();
}
tweenManager = new TweenManager();
AnimationThread aniThread = new AnimationThread();
aniThread.setManager(tweenManager);
aniThread.start();
Tween.to(p, 1, 10.0f).target(600).ease(Quad.OUT).start(tweenManager);
}
public void setupGUI() throws IOException {
JFrame f = new JFrame();
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new TweeningPane();
JLabel l = new JLabel(new ImageIcon("E:/Pictures/Stream/aK6IX4V.png"));
f.setLayout(null);
p.add(l);
p.setBounds(0, 0, 300, 300);
f.add(p);
f.setVisible(true);
}
}
AnimationThread.java - The Thread, that is supposed to keep my TweenManager updated as much/often as possible
public class AnimationThread extends Thread {
TweenManager tm;
public void setManager(TweenManager tweenmanager) {
this.tm = tweenmanager;
}
public void run() {
while (true) {
//System.out.println("MyThread running");
tm.update(MAX_PRIORITY);
try {
sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
TweeningPane.java - My Object(JPanel), I want to move across the JPanel
public class TweeningPane extends JPanel implements TweenAccessor<JPanel> {
private static final long serialVersionUID = 1L;
#Override
public int getValues(JPanel arg0, int arg1, float[] arg2) {
return (int) arg0.getBounds().getX();
}
#Override
public void setValues(JPanel arg0, int arg1, float[] arg2) {
arg0.setBounds((int) arg2[0], 0, 300, 300);
}
}
I have finally figured it out. I was simply using the framework in a wrong way as I expected. I'm not sure whether all these steps were needed but this is what I went through in order to make it work: (for future reference)
I had to register my accessor to the engine:
Tween.registerAccessor(TweeningPane.class, new TweeningPane());
And the thread itself now looks like this; I had to give the manager's update method the elapsed time as a parameter.
public void run() {
long ms1 = System.currentTimeMillis();
while (true) {
//System.out.println("MyThread running");
tm.update((System.currentTimeMillis() - ms1) / 1000f);
try {
Thread.sleep(40);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I've looked over the stackoverflow and the internet and I couldn't find a clear answer that helped me.
I have an assignment and it includes the following class, which is a GUI. I have Junit tested the other classes but for this I didn't know how.
import java.awt.*;
public class CruiseDisplay extends Canvas {
private int recorded = 0; //recorded speed
private boolean cruiseOn = false; //cruise control state
private final static int botY = 200;
private Font small = new Font("Helvetica",Font.BOLD,14);
private Font big = new Font("Helvetica",Font.BOLD,18);
public CruiseDisplay() {
super();
setSize(150,260);
}
Image offscreen;
Dimension offscreensize;
Graphics offgraphics;
public void backdrop() {
Dimension d = getSize();
if ((offscreen == null) || (d.width != offscreensize.width)
|| (d.height != offscreensize.height)) {
offscreen = createImage(d.width, d.height);
offscreensize = d;
offgraphics = offscreen.getGraphics();
offgraphics.setFont(small);
}
offgraphics.setColor(Color.black);
offgraphics.fillRect(0, 0, getSize().width, getSize().height);
offgraphics.setColor(Color.white);
offgraphics.drawRect(5,10,getSize().width-15,getSize().height-40);
offgraphics.setColor(Color.blue);
offgraphics.fillRect(6,11,getSize().width-17,getSize().height-42);
}
public void paint(Graphics g) {
update(g);
}
public void update(Graphics g) {
backdrop();
// display recorded speed
offgraphics.setColor(Color.white);
offgraphics.setFont(big);
offgraphics.drawString("Cruise Control",10,35);
offgraphics.setFont(small);
drawRecorded(offgraphics,20,80,recorded);
if (cruiseOn)
offgraphics.drawString("Enabled",20,botY+15);
else
offgraphics.drawString("Disabled",20,botY+15);
if (cruiseOn)
offgraphics.setColor(Color.green);
else
offgraphics.setColor(Color.red);
offgraphics.fillArc(90,botY,20,20,0,360);
g.drawImage(offscreen, 0, 0, null);
}
public void drawRecorded(Graphics g, int x, int y, int speed) {
g.drawString("Cruise Speed",x,y+10);
g.drawRect(x+20,y+20,50,20);
g.setFont(big);
g.drawString(String.valueOf(speed+20),x+30,y+37);
g.setFont(small);
}
public void enabled() {
cruiseOn = true;
repaint();
}
public void disabled() {
cruiseOn = false;
repaint();
}
public void record(int speed) {
recorded=speed;
repaint();
}
}
Can somebody help me please?
I'm trying to make a small square move across the top of the panel. I'm not worried about the seamlessness of the animation or flicker or anything like that. It appears that in the while-loop, repaint() isn't repeatedly calling the paintComponent. Thoughts?
public class NodeMove extends JFrame {
boolean running = true;
public NodeMove() {
widgetNode panel = new widgetNode();
add(panel);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
Runnable node = new widgetNode();
Thread thread1 = new Thread(node);
thread1.start();
}
class widgetNode extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
private int x = 30;
private int y = 30;
public widgetNode() {
}
public void run(){
while(running){
nodeUpdate();
repaint();
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
public void nodeUpdate(){
x += 4;
}
protected void paintComponent(Graphics g) {
super.paintComponents(g);
g.drawRect(x, y, 30, 30);
}
}
public static void main(String[] args) {
NodeMove frame = new NodeMove();
for(int i = 0; i < 50; i++){
frame.repaint();
}
}
}
I managed to increase an image of JLabel(which has an imageIcon stored in). When I press the increase size button, the original size of the image is increased on the panel, which is exactly what I want. However, when I click on my decrease size button(I figured dividing it by the scale might fix it)the label decreases, but the actual image appearance(size I guess)is changed. It's not decreasing the size, the same way my increase button increases the size. I have spent hours trying to figure out why by multiplying it, I am able to increase the size of a the label and the image in it(which implies that not just the label is increasing, the actual image is too)but for decrease(I'm dividing instead of multiplying)it doesn't work. Here is both my increase and decrease listener.
public class IncreaseSizeListener implements ActionListener {
static JLabel increasedLabel;
#Override
public void actionPerformed(ActionEvent e) {
increasedLabel = CardLabelListener.selectedLabel;
Icon icon = CardLabelListener.selectedLabel.getIcon();
int scale =2;
System.out.println("Increased size fired");
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
scale*icon.getIconWidth(),
scale*icon.getIconHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
CardLabelListener.selectedLabel.setSize(icon.getIconWidth()*scale, icon.getIconHeight()*(scale));
CardLabelListener.selectedLabel.setIcon(temp.getIcon());
CardLabelListener.selectedLabel.updateUI();
}
}
public class DecreaseSizeListener implements ActionListener {
static JLabel increasedLabel;
#Override
public void actionPerformed(ActionEvent e) {
increasedLabel = CardLabelListener.selectedLabel;
Icon icon = CardLabelListener.selectedLabel.getIcon();
int scale =2;
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
icon.getIconWidth()/scale,
icon.getIconHeight()/scale,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
CardLabelListener.selectedLabel.setSize( (icon.getIconWidth()/scale), (icon.getIconHeight()/(scale)));
CardLabelListener.selectedLabel.setIcon(temp.getIcon());
CardLabelListener.selectedLabel.updateUI();
}
}
Change g.scale(scale,scale); to g.scale(0.5d,0.5d); in your decrease action listener
Or you could do this...
int scale = 0.5;
//I can now resize images, based on my needs
BufferedImage bi = new BufferedImage(
icon.getIconWidth() * scale,
icon.getIconHeight() * scale,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale,scale);
icon.paintIcon(null,g,0,0);
g.dispose();
// This really isn't required...
//JLabel temp = new JLabel(new ImageIcon(bi));
//to ensure proper size is kept for the enlarged image
// There is a better way...
//CardLabelListener.selectedLabel.setSize( (icon.getIconWidth()/scale), (icon.getIconHeight()/(scale)));
// This isn't required
//CardLabelListener.selectedLabel.setIcon(temp.getIcon());
// This doesn't do what you think it does...
//CardLabelListener.selectedLabel.updateUI();
CardLabelListener.selectedLabel.setIcon(new ImageIcon(bi));
CardLabelListener.selectedLabel.setSize(CardLabelListener.selectedLabel.getPreferredSize());
Now both the increase and decrease algorithm's are just about the same (except for the factor), you should be able to use a single method ;)
This is pretty much the code I ended up with...
public class ScaleMyIcon {
public static void main(String[] args) {
new ScaleMyIcon();
}
public ScaleMyIcon() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScaleMyIconPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class ScaleMyIconPane extends JPanel {
public ScaleMyIconPane() {
setLayout(new BorderLayout());
ImageIcon image = null;
try {
image = new ImageIcon(ImageIO.read(getClass().getResource("/stormtrooper-tie.jpg")));
} catch (IOException ex) {
ex.printStackTrace();
}
JLabel label = new JLabel(image);
add(label);
JPanel buttons = new JPanel();
JButton increase = new JButton("+");
JButton decrease = new JButton("-");
buttons.add(increase);
buttons.add(decrease);
increase.addActionListener(new IncreaseSizeListener(label));
decrease.addActionListener(new DecreaseSizeListener(label));
add(buttons, BorderLayout.SOUTH);
}
}
public class Scaler {
public Icon getScaledInstance(Icon original, double scale) {
BufferedImage bi = new BufferedImage(
(int)Math.round(scale * original.getIconWidth()),
(int)Math.round(scale * original.getIconHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale, scale);
original.paintIcon(null, g, 0, 0);
g.dispose();
return new ImageIcon(bi);
}
}
public class IncreaseSizeListener extends Scaler implements ActionListener {
private JLabel increasedLabel;
private IncreaseSizeListener(JLabel label) {
increasedLabel = label;
}
#Override
public void actionPerformed(ActionEvent e) {
Icon icon = increasedLabel.getIcon();
int scale = 2;
increasedLabel.setIcon(getScaledInstance(icon, scale));
}
}
public class DecreaseSizeListener extends Scaler implements ActionListener {
private JLabel decreasedLabel;
private DecreaseSizeListener(JLabel label) {
decreasedLabel = label;
}
#Override
public void actionPerformed(ActionEvent e) {
Icon icon = decreasedLabel.getIcon();
decreasedLabel.setIcon(getScaledInstance(icon, 0.5d));
}
}
}
UPDATED with different approach
While I was mucking around with it, I noticed two issues. There was no coalition between the up and down scales and you were never using the original image to scale against, you were always scaling the dirty image. Try scaling the image down and back up again.
This is my take on how to overcome those issues
public class ScaleMyIcon {
public static void main(String[] args) {
new ScaleMyIcon();
}
public ScaleMyIcon() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScaleMyIconPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class ScaleMyIconPane extends JPanel {
public ScaleMyIconPane() {
setLayout(new BorderLayout());
ImageIcon image = null;
try {
image = new ImageIcon(ImageIO.read(getClass().getResource("/stormtrooper-tie.jpg")));
} catch (IOException ex) {
ex.printStackTrace();
}
JLabel label = new JLabel(image);
add(label);
JPanel buttons = new JPanel();
JButton increase = new JButton("+");
JButton decrease = new JButton("-");
buttons.add(increase);
buttons.add(decrease);
increase.addActionListener(new IncreaseSizeListener(label));
decrease.addActionListener(new DecreaseSizeListener(label));
add(buttons, BorderLayout.SOUTH);
}
}
public static class Scalable {
private JLabel label;
private Icon original;
private static double scale = 1;
private Scalable(JLabel label) {
this.label = label;
original = label.getIcon();
}
public JLabel getLabel() {
return label;
}
public double getScale() {
return scale;
}
public void setScale(double scale) {
this.scale = scale;
}
public void incrementScale(double factor) {
setScale(getScale() + factor);
}
public Icon getScaledInstance() {
BufferedImage bi = new BufferedImage(
(int) Math.round(scale * original.getIconWidth()),
(int) Math.round(scale * original.getIconHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.scale(scale, scale);
original.paintIcon(null, g, 0, 0);
g.dispose();
return new ImageIcon(bi);
}
}
public class IncreaseSizeListener extends Scalable implements ActionListener {
public IncreaseSizeListener(JLabel label) {
super(label);
}
#Override
public void actionPerformed(ActionEvent e) {
incrementScale(0.05);
getLabel().setIcon(getScaledInstance());
}
}
public class DecreaseSizeListener extends Scalable implements ActionListener {
private DecreaseSizeListener(JLabel label) {
super(label);
}
#Override
public void actionPerformed(ActionEvent e) {
incrementScale(-0.05);
getLabel().setIcon(getScaledInstance());
}
}
}