two balls from left and bottom colliding with each other as they meet at a certain coordinate. I have already did what I searched on the internet and it worked perfectly, but I need a start, pause and resume buttons. Look at what I finished :
import java.applet.Applet;
import java.awt.Button;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class train extends Applet implements Runnable,ActionListener {
private volatile boolean runs = true;
private Image i;
private Graphics doubleG;
Ball b, b2;
Button x,y,z;
Thread thread = new Thread(this);
#Override
public void init(){
setSize(800, 600);
x = new Button("Action!");
y = new Button("Stop");
z = new Button("Resume!");
add(x);
add(y);
add(z);
y.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e)
{
runs = false;
repaint();
}
});
z.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e)
{
try {
runs = true;
b.update(this);
repaint();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
b2.update2(this);
repaint();
}
});
}
#Override
public void start(){
x.addActionListener(this);
b = new Ball(100, 100);
b2 = new Ball(500, 500);
}
#Override
public void run(){
while(runs){
b.update(this);
b2.update2(this);
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
#Override
public void stop(){
}
#Override
public void destroy(){
}
#Override
public void update(Graphics g) {
// TODO Auto-generated method stub
if(i == null){
i = createImage(this.getSize().width, this.getSize().height);
doubleG = i.getGraphics();
}
doubleG.setColor(getBackground());
doubleG.fillRect(0, 0, this.getSize().width, this.getSize().height);
doubleG.setColor(getForeground());
paint(doubleG);
g.drawImage(i, 0, 0, this);
}
#Override
public void paint(Graphics g){
b.paint(g);
b2.paint(g);
}
public void actionPerformed(ActionEvent e) {
thread.start();
}
}
for the main train.class and :
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
public class Ball {
private int x;
private int y;
private double dx = 7.9;
private double dy = 7;
private int radius = 20;
public Ball() {
// TODO Auto-generated constructor stub
}
public Ball(int i, int j) {
// TODO Auto-generated constructor stub
x = i;
y = j;
}
public void update(train sp){
x += dx;
// if(x + dx > sp.getSize().width - 300){
// dx=0;
// }
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillOval(x-radius, y-radius, radius * 2, radius * 2);
}
public void update2(train sp){
y -= dy;
if(y - dy < sp.getSize().height - 470){
x += dx;
y -= dy;
// if(y < sp.getSize().height - 470){
// y = sp.getSize().height -470;
// dy *= energyloss;
// dy = -dy;
// }else{
// dy += gravity * dt;
// y += dy*dt + .5 * gravity * dt * dt;
}
//}
}
public void update(ActionListener actionListener) throws InterruptedException {
x += dx;
}
public void update2(ActionListener actionListener) {
train tr = new train();
if(y - dy < tr.getSize().height - 470){
x += dx;
y -= dy;
}else{
y-=dy;
}
}
}
What I want to do is I want to make a resume button. I already finished the start and pause, but when I click the resume button, it just moves 1 coordinate at a time. I need it to just like Start , pause and play normally. Please help. T_T
An easy fix is to not have "runs" control the loop, but just determine whether or not the update method is called. That way you don't break the loop and have to restart.
Related
This question already has answers here:
How to use Key Bindings instead of Key Listeners
(4 answers)
Closed 5 years ago.
When VK_UP or VK_DOWN is pressed the Graphic g I created is not changing its position whatsoever. If someone could look and see if there is something wrong with my move method etc. Would really appreciate it.
Here is all my code so far:
package ping2;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Ping2 extends Applet implements Runnable, KeyListener{
final int WIDTH = 700, HEIGHT = 500;
Thread thread;
UserPaddle user1;
public void init() {
this.resize(WIDTH, HEIGHT);
this.addKeyListener(this);
user1 = new UserPaddle(1);
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
user1.draw(g);
}
public void update(Graphics g) {
paint(g);
}
public void run() {
for(;;) {
user1.move();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP) {
user1.setUpAccel(true);
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
user1.setDownAccel(true);
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP) {
user1.setUpAccel(false);
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
user1.setDownAccel(false);
}
}
public void keyTyped(KeyEvent arg0) {
}
}
package ping2;
import java.awt.*;
public class UserPaddle implements InterfaceBar{
double y, yVelocity;
boolean upAccel, downAccel;
int player1, x;
final double FRICTION = 0.90;
public UserPaddle(int player1) {
upAccel = false;
downAccel = false;
y = 210;
yVelocity = 0;
if(player1 == 1)
x = 20;
else
x = 660;
}
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillRect(x, (int)y, 20, 80);
}
public void move() {
if(upAccel) {
yVelocity -= 2;
}else if(downAccel) {
yVelocity += 2;
}
//Automatically slows bar down if key not being pressed.
else if(!upAccel && !downAccel) {
yVelocity *= FRICTION;
}
}
public void setUpAccel(boolean input) {
upAccel = input;
}
public void setDownAccel(boolean input) {
downAccel = input;
}
public int getY() {
return (int)y;
}
}
package ping2;
import java.awt.Graphics;
public interface InterfaceBar {
public void draw(Graphics g);
public void move();
public int getY();
}
I have modified your move() a bit give it a try
move()
public void move() {
if(upAccel) {
yVelocity -= 2;
y = yVelocity;
}else if(downAccel) {
yVelocity += 2;
y = yVelocity;
}
}
I'm coding a game so that when you hold D the character moves right and when you hold S the character moves left. The program works just as it should, with one exception. As I'm moving the character (and the character moves perfectly fine), java keeps throwing the error "java.util.ConcurrentModificationException". I did some research and learned that I cannot be adding to the ArrayList "keys" and be iterating it at the same time. With that said, how do I edit the code to still have the character move seamlessly as he is now? This is the only way I know of to make sure the character moves at the same steady pace the second you hold a key down, not take a quick movement, pause, and then continue with the motion.
package LevelEditor;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.Iterator;
public class LevelEditor extends Canvas implements KeyListener, Runnable, MouseListener, MouseMotionListener{
private Object[][] grid = new Object[50][50];
private Graphics bufferGraphics = null; //The graphics for the back buffer
private BufferStrategy bufferStrategy = null;
private Thread thread;
private boolean running;
private int selectedBlock = 0;
private int mouseX;
private int mouseY;
private int playerX;
private int playerY;
private ArrayList<Integer> keys = new ArrayList<Integer>();
Iterator itr;
Player player1;
public LevelEditor(Dimension size){
//Constructor
this.setPreferredSize(size);
this.addKeyListener(this);
this.thread = new Thread(this);
this.addMouseListener(this);
this.addMouseMotionListener(this);
running = true;
mouseX = 0;
mouseY = 0;
playerX = 0;
playerY = 0;
itr = keys.iterator();
}
public void paint(Graphics g){
if (bufferStrategy == null){
this.createBufferStrategy(2);
bufferStrategy = this.getBufferStrategy();
bufferGraphics = bufferStrategy.getDrawGraphics();
player1 = new Player(playerX, playerY);
this.thread.start();
}
}
#Override
public void run() {
//This is what runs when level editor is running
while (running){
//Program's logic
DoLogic();
Draw();
DrawBackbufferToScreen();
Thread.currentThread();
try{
Thread.sleep(10);
}
catch(Exception e){
e.printStackTrace();
}
}
}
public void DoLogic(){
}
public void Draw(){
//clear secondary screen
bufferGraphics = bufferStrategy.getDrawGraphics();
try{
bufferGraphics.clearRect(0, 0, this.getSize().width, this.getSize().height);
//this is where everything will be drawn to back buffer
for (int x = 0; x < grid.length; x++){
for(int y = 0; y < grid[x].length; y++){
Object o = grid[x][y];
if (o instanceof Block){
Block blocktoDraw = (Block)o;
blocktoDraw.draw(bufferGraphics);
}
}
}
Block.getBlock(selectedBlock, mouseX, mouseY).draw(bufferGraphics);
player1.draw(bufferGraphics);
for (Integer x : keys){
if(x == 68 && itr.hasNext()){
playerX += 5;
player1.updatePlayer(playerX, playerY);
player1.draw(bufferGraphics);
itr.next();
itr.remove();
}
if (x == 65 && itr.hasNext()){
playerX -= 5;
player1.updatePlayer(playerX, playerY);
player1.draw(bufferGraphics);
itr.next();
itr.remove();
}
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
bufferGraphics.dispose();
}
}
public void DrawBackbufferToScreen(){
bufferStrategy.show();
Toolkit.getDefaultToolkit().sync();
}
#Override
public void mouseReleased(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
mouseX = (mouseX / 25);
mouseY = (mouseY / 25);
if (e.getModifiers() == 16){
grid[mouseX][mouseY] = Block.getBlock(selectedBlock, mouseX, mouseY);
}
else if (e.getModifiers() == 4){
grid[mouseX][mouseY] = Block.getBlock(100, mouseX, mouseY);
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
keys.clear();
}
#Override
public void keyPressed(KeyEvent e) {
keys.add(e.getKeyCode());
}
public void mouseMoved(MouseEvent e) {
this.mouseX = e.getX() / 25;
this.mouseY = e.getY() / 25;
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
mouseX = (mouseX / 25);
mouseY = (mouseY / 25);
if(e.MOUSE_DRAGGED == 506 && e.getModifiers() == 16){
grid[mouseX][mouseY] = Block.getBlock(selectedBlock, mouseX, mouseY);
}
else if (e.MOUSE_DRAGGED == 506 && e.getModifiers() == 4){
grid[mouseX][mouseY] = Block.getBlock(100, mouseX, mouseY);
}
}
}
Using an Iterator is the wrong model here: you aren't actually iterating through the list, you are just looking to see if you have an element, and then processing it if you have something.
A better fit is to use a queue - particularly, some sort of concurrent queue, e.g. java.util.concurrent.BlockingQueue, since you are modifying it and reading it in different threads.
You can add key codes into this using queue.add(e.getKeyCode()), and remove them using queue.poll() (or queue.peek()), which returns a null value if there is nothing in the queue (akin to itr.hasNext() being false).
I'm working on a game project. The aim is clicking the balls and drop them into the basket which is below in the JPanel. I created some ways to do that but I can't achieve it. In my opinion, when the user click the ball's center with a margin of error (because the program can't catch the real point of balls), the program understands the action and runs the function of this issue. After clicking the ball it should be dropped down straight but the other balls should be continued. I use MouseListener#mousePressed method, but it doesn't work or I'm missing some parts. In addition, I made some changes in my source code, but I want to listen your advices so I am writing this topic.
I wrote a method which finds the mouse and ball coordinates. So when I make some changes to it, I can achieve my project goal. You can see the editing in the picture.
This is my source code ;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game {
public Game() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("MultipleBallApp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BallControl());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BallControl extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private BallPanel ballPanel = new BallPanel();
private JButton Suspend = new JButton("Suspend");
private JButton Resume = new JButton("Resume");
private JButton Add = new JButton("+1");
private JButton Subtract = new JButton("-1");
private JScrollBar Delay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(Suspend);
panel.add(Resume);
panel.add(Add);
panel.add(Subtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
Delay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(Delay.getMaximum());
setLayout(new BorderLayout());
add(Delay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent clickEvent) {
// TODO Auto-generated method stub
System.out.println("X coordinate =" + clickEvent.getX());
System.out.println("Y coordinate = " + clickEvent.getY());
double radius1;
int x = 0;
double y = 0;
int radius = 15;
double xM = clickEvent.getX();
double yM = clickEvent.getY();
radius1 = Math.sqrt((xM - x) * (xM - x) + (yM - y)
* (yM - y));
System.out.println("Radius1 =" + radius1);
// ballPanel.list.get(0).setD
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
// Register listeners
Suspend.addActionListener(new Listener());
Resume.addActionListener(new Listener());
Add.addActionListener(new Listener());
Subtract.addActionListener(new Listener());
Delay.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(Delay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Suspend) {
ballPanel.suspend();
} else if (e.getSource() == Resume) {
ballPanel.resume();
} else if (e.getSource() == Add) {
ballPanel.add();
} else if (e.getSource() == Subtract) {
ballPanel.subtract();
}
}
}
}
class BallPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private int delay = 30;
public ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();
private AnimatedRectange rectangle;
public BallPanel() {
this.rectangle = new AnimatedRectange(-25, 373, 50, 25, Color.BLACK);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
// Create a timer with the initial delay
protected Timer timer = new Timer(delay, new ActionListener() {
/**
* Handle the action event
*/
#Override
public void actionPerformed(ActionEvent e) {
for (AnimatedShape ball : list) {
ball.update(getBounds());
}
rectangle.update(getBounds());
repaint();
}
});
public void add() {
int radius = 15;
// Randomised position
int x = (int) (Math.random() * (getWidth() - (radius * 2)))
+ radius;
int y = (int) (Math.random() * (getHeight() - (radius * 2)))
+ radius;
Color color = new Color((int) (Math.random() * 256),
(int) (Math.random() * 256), (int) (Math.random() * 256));
AnimatedBall ball = new AnimatedBall(x, y, radius, color);
list.add(ball);
}
// public void formula(MouseEvent clickEvent) {
// double radius1;
// int x = 0;
// double y = 0;
// int radius = 15;
// double xM = clickEvent.getX();
// double yM = clickEvent.getY();
// radius1 = Math.sqrt((xM - x) * (xM - x) + (yM - y) * (yM - y));
// System.out.println("Radius1 =" + radius1);
// }
public void subtract() {
if (list.size() > 0) {
list.remove(list.size() - 1); // Remove the last ball
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (AnimatedShape ball : list) {
ball.paint(this, g2d);
}
rectangle.paint(this, g2d);
}
public void suspend() {
timer.stop();
}
public void resume() {
timer.start();
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
}
public interface AnimatedShape {
public void update(Rectangle bounds);
public void paint(JComponent parent, Graphics2D g2d);
}
public abstract class AbstractAnimatedShape implements AnimatedShape {
private Rectangle bounds;
private int dx, dy;
public AbstractAnimatedShape() {
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Rectangle getBounds() {
return bounds;
}
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(int dy) {
this.dy = dy;
}
#Override
public void update(Rectangle parentBounds) {// ball
Rectangle bounds = getBounds();
int dx = getDx();
int dy = getDy();
bounds.x += dx;
bounds.y += dy;
if (bounds.x < parentBounds.x) {
bounds.x = parentBounds.x;
setDx(dx *= -1);
} else if (bounds.x + bounds.width > parentBounds.x
+ parentBounds.width) {
bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
setDx(dx *= -1);
}
if (bounds.y < parentBounds.y) {
bounds.y = parentBounds.y;
setDy(dy *= -1);
} else if (bounds.y + bounds.height > parentBounds.y
+ parentBounds.height) {
bounds.y = parentBounds.y
+ (parentBounds.height - bounds.height);
setDy(dy *= -1);
}
}
}
public class AnimatedBall extends AbstractAnimatedShape {
private Color color;
public AnimatedBall(int x, int y, int radius, Color color) {
setBounds(new Rectangle(x, y / 2, radius * 2, radius * 2));
this.color = color;
setDx(Math.random() > 0.5 ? 2 : -2);
// setDy(Math.random() > 0.5 ? 2 : -2);
}
public Color getColor() {
return color;
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(getColor());
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
public class AnimatedRectange extends AbstractAnimatedShape {
private Color color;
public AnimatedRectange(int x, int y, int width, int height, Color color) {
setBounds(new Rectangle(x, y, width, height));
this.color = color;
setDx(2);
}
// Don't want to adjust the vertical speed
#Override
public void setDy(int dy) {
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(color);
g2d.fill(bounds);
}
}
/**
* Main method
*/
public static void main(String[] args) {
new Game();
}
}
At the end of your mousePressed method, you can go though all AnimatedShape objects, check whether they are an AnimatedBall. When the object is a ball, you can test whether the mouse click hits the ball. The mouse click hits the ball when the distance between the center of the ball and the mouse position is smaller than the ball radius. When the ball is hit, you can set its horizontal speed to 0, and the vertical speed to 5 or so.
for (AnimatedShape as : ballPanel.list)
{
if (as instanceof AnimatedBall)
{
AnimatedBall ball = (AnimatedBall)as;
Rectangle b = ball.getBounds();
int ballCenterX = b.x + b.width / 2;
int ballCenterY = b.y + b.height / 2;
Point p = new Point(ballCenterX, ballCenterY);
double d = p.distance(clickEvent.getPoint());
if (d < radius)
{
ball.setDx(0);
ball.setDy(5);
}
}
}
Note
In order to make this work properly, you have to attach this listener to the ballPanel. Originally, you had the line
this.addMouseListener(new MouseListener() {
in your code. You have to change this to
ballPanel.addMouseListener(new MouseListener() {
Otherwise, the mouse coordinates will refer to the wrong component!
Concerning the question from the comment
how can I stop and disapper clickedball's when they crash the bound
You may probably insert method to check this, and call this method in the actionPerformed method of your timer. Further explainations are probably beyond the scope of an anser on a Q&A site. Stackoverflow is not a homework-solution-generator.
I'm very new to game design (this is my first attempt) and this project will be used to create an android game.
I'm trying to make a simple game (as simple as possible).
What I need:
A background
a ship (that can move left an right at the bottom of the screen)
Enemies (Bombs dropping down from the sky)
projectiles (to shoot bombs with, shoot straight up)
Score (in the upper corner)
I have studied this tutorial:
http://www.kilobolt.com/game-development-tutorial.html
and changed code to get this:
http://i297.photobucket.com/albums/mm231/mabee84/Battleship.png
the black rectangles are projectiles.
Now I need to create the bombs but I can't figure out how to implement them.
they need to spawn at fixed y-value and a random x-value (within the screen)
Upon shooting on the bombs they should die but if bombs hit the ship game is over.
Please help i'm a bit stuck.
package kiloboltgame;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
import java.util.ArrayList;
public class StartingClass extends Applet implements Runnable, KeyListener {
private Ship ship;
public static Bomb b1, b2;
public static int score = 0;
private Font font = new Font(null, Font.BOLD, 30);
private Image image, Battleship, Background, Bomb;
private static Background bg1, bg2;
private URL base;
private Graphics second;
#Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("BattleShip");
try{
base = getDocumentBase();
}catch (Exception e){
//TODO: handle exception
}
//Image Setups
Battleship = getImage(base, "data/Battleship.png");
Background = getImage(base, "data/Background.png");
Bomb = getImage(base, "data/Bomb1.png");
}
#Override
public void start() {
bg1 = new Background(0, 0);
bg2 = new Background(800, 0);
ship = new Ship();
b1 = new Bomb(340, 100);
b2 = new Bomb(700, 100);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void stop() {
// TODO Auto-generated method stub
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void run() {
while (true) {
ship.update();
ArrayList projectiles = ship.getProjectiles();
for(int i = 0; i < projectiles.size(); i++){
Projectile p = (Projectile) projectiles.get(i);
if(p.isVisible() == true){
p.update();
}else{
projectiles.remove(i);
}
}
b1.update();
b2.update();
bg1.update();
bg2.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void update(Graphics g) {
if(image == null){
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
#Override
public void paint(Graphics g) {
g.drawImage(Background, bg1.getBgX(), bg1.getBgY(), this);
ArrayList projectiles = ship.getProjectiles();
for(int i = 0; i < projectiles.size(); i++){
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.BLACK);
g.fillRect(p.getX(), p.getY(), 5, 10);
}
g.drawImage(Battleship, ship.getCenterX() + 230, ship.getCenterY() -23, this);
g.drawImage(Bomb, b1.getCenterX() - 20, b1.getCenterY() - 20, this);
g.drawImage(Bomb, b2.getCenterX() - 20, b2.getCenterY() - 20, this);
g.setFont(font);
g.setColor(Color.BLACK);
g.drawString(Integer.toString(score), 710, 30);
}
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_LEFT:
ship.moveLeft();
break;
case KeyEvent.VK_RIGHT:
ship.moveRight();
break;
case KeyEvent.VK_CONTROL:
ship.shoot();
score = score +100;
break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
ship.stop();
break;
case KeyEvent.VK_RIGHT:
ship.stop();
break;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static Background getBg1() {
return bg1;
}
}
package kiloboltgame;
import java.util.ArrayList;
public class Ship {
//In Java, Class Variables should be private so that only its methods can change them.
private int centerX = 100;
private int centerY = 382;
private int speedX = 0;
private int speedY = 1;
private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
} else if (speedX == 0) {
System.out.println("Do not scroll the background.");
} else {
if (centerX <= 440) {
centerX += speedX;
} else {
System.out.println("Scroll Background Here");
}
}
// Updates Y Position
if (centerY + speedY >= 382) {
centerY = 382;
}else{
centerY += speedY;
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= -230) {
centerX = -229;
}
}
public void moveRight() {
speedX = 6;
}
public void moveLeft() {
speedX = -6;
}
public void shoot(){
Projectile p = new Projectile(centerX + 285, centerY -10);
projectiles.add(p);
}
public ArrayList getProjectiles(){
return projectiles;
}
public void stop() {
speedX = 0;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public int getSpeedX() {
return speedX;
}
public int getSpeedY() {
return speedY;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
}
package kiloboltgame;
public class Background {
private int bgX, bgY, speedX;
public Background(int x, int y){
bgX = x;
bgY = y;
speedX = 0;
}
public void update() {
bgX += speedX;
if (bgX <= -800){
bgX += 1600;
}
}
public int getBgX() {
return bgX;
}
public int getBgY() {
return bgY;
}
public int getSpeedX() {
return speedX;
}
public void setBgX(int bgX) {
this.bgX = bgX;
}
public void setBgY(int bgY) {
this.bgY = bgY;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
}
public class Projectile {
private int x, y, speedY;
private boolean visible;
public Projectile(int startX, int startY) {
x = startX;
y = startY;
speedY = -7;
visible = true;
}
public void update() {
y += speedY;
if(y > 480){
visible = false;
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getSpeedY() {
return speedY;
}
public boolean isVisible() {
return visible;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
}
package kiloboltgame;
public class Enemy {
private int maxHealth, currentHealth, power, speedX, centerX, centerY;
private Background bg = StartingClass.getBg1();
//Behavioral Methods
public void update(){
centerX += speedX;
speedX = bg.getSpeedX();
}
public void die(){
}
public void attack(){
}
public int getMaxHealth() {
return maxHealth;
}
public int getCurrentHealth() {
return currentHealth;
}
public int getPower() {
return power;
}
public int getSpeedX() {
return speedX;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public Background getBg() {
return bg;
}
public void setMaxHealth(int maxHealth) {
this.maxHealth = maxHealth;
}
public void setCurrentHealth(int currentHealth) {
this.currentHealth = currentHealth;
}
public void setPower(int power) {
this.power = power;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setBg(Background bg) {
this.bg = bg;
}
}
package kiloboltgame;
public class Bomb extends Enemy {
public Bomb(int centerX, int centerY) {
setCenterX(centerX);
setCenterY(centerY);
}
}
This is all code that i have so far (I know the background is f*ed since the game this is based on is scrolling right and i haven't fixed it yet.
I recommend putting all object creation in a seperate part of the program. I'd make a BombFactory with a makeBomb mathod that returns a new Bomb instance. Inside the factory, figure out the x-coordinate, for instance using a randomiser. As parameters, you could specify a y-coordinate and possibly an upper and lower bound for the x. This way you can make new Bombs on the fly.
public class BombFactory {
private final Random rand;
public BombFactory() {
this.rand = new Random();
}
public Bomb makeBomb(int lowerboundX, int rangeX, int yPos) {
final int xPos = lowerboundX + rand.nextInt(rangeX);
return new Bomb(xPos, yPos);
}
}
As for the behaviour, I'd look into inheritance and interfaces some more. I see a lot of methods occurring more than once. You generally want to avoid that kind of duplication. You can start by taking all the methods having something to do with coords or movement and putting them in an abstract base class.
You can make a method inside Enemy that checks for a collision and responds to that in different ways, depending on how the subclass overrides it. In case of a Bomb, it would probably always kill itself and whatever it came in contact with.
I'm trying to develop a 2D RPG Game in a Java Applet. Right now I've got a simple oval that the player can use Left, Right, Up and Down to move, and collisions against the borders of the applet stops them. The problem is, I want to create a giant world(2000px by 2000x) of area that the player can move. However, I want them only to see 600px by 400x of the screen at one time. If they keep moving right, I want the screen to follow them, same goes for up, down and left. Can anyone tell me how to do this? Here is my code so far:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.Applet;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Main extends Applet implements Runnable, KeyListener
{
private Image dbImage;
private Graphics dbg;
Thread t1;
int x = 0;
int y = 0;
int prevX = x;
int prevY = y;
int radius = 40;
boolean keyReleased = false;
public void init()
{
setSize(600, 400);
}
public void start()
{
addKeyListener(this);
t1 = new Thread(this);
t1.start();
}
public void destroy()
{
}
public void stop()
{
}
public void paint(Graphics g)
{
//player
g.setColor(Color.RED);
g.fillOval(x, y, radius, radius);
}
public void update(Graphics g)
{
dbImage = createImage (this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
// initialize buffer
if (dbImage == null)
{
}
// clear screen in background
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbg.setColor(getForeground());
paint(dbg);
// draw image on the screen
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run()
{
while (true)
{
//x++;
repaint();
try
{
t1.sleep(17);
}
catch (Exception e)
{
}
}
}
public boolean CheckCollision(String dir)
{
if (x <= 0 && dir.equals("L"))
{
x = prevX;
return true;
}
else if (y <= 0 && dir.equals("U"))
{
y = prevY;
return true;
}
else if (x >= (getWidth() - radius) && dir.equals("R"))
{
System.out.println(getWidth());
x = prevX;
return true;
}
else if (y >= (getHeight() - radius) && dir.equals("D"))
{
y = prevY;
return true;
}
return false;
}
#Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_RIGHT:
if (!CheckCollision("R"))
{
x += 4;
prevX = x;
}
break;
case KeyEvent.VK_LEFT:
if (!CheckCollision("L"))
{
x -= 4;
prevX = x;
}
break;
case KeyEvent.VK_UP:
if (!CheckCollision("U"))
{
y -= 4;
prevY = y;
}
break;
case KeyEvent.VK_DOWN:
if (!CheckCollision("D"))
{
y += 4;
prevY = y;
}
break;
}
}
#Override
public void keyReleased(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
}
This is a basic example of scrolling viewable area, where the virtual world is large then the view area.
This basically maintains a number of parameters. It maintains the point where in the world the top/left of the view is and the players position within the world.
These values are converted back to real world coordinates (where 0x0 is the top left corner of the viewable area).
The examples also use BufferedImage#getSubImage to make it easier to render. You could calculate the offset position of the map to the view as well, but that comes down to needs...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MiddleEarth {
public static void main(String[] args) {
new MiddleEarth();
}
public MiddleEarth() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new WorldPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class WorldPane extends JPanel {
private BufferedImage map;
private BufferedImage party;
private Point viewPort;
private Point partyPoint;
private BufferedImage view;
public WorldPane() {
try {
map = ImageIO.read(getClass().getResource("/MiddleEarth.jpg"));
party = ImageIO.read(getClass().getResource("/8BitFrodo.png"));
viewPort = new Point(0, (map.getHeight() / 2) - 100);
partyPoint = new Point(party.getWidth() / 2, (map.getHeight() / 2)); // Virtual Point...
} catch (IOException exp) {
exp.printStackTrace();
}
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "goUp");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "goDown");
am.put("goRight", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(10, 0);
}
});
am.put("goLeft", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(-10, 0);
}
});
am.put("goUp", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(0, -10);
}
});
am.put("goDown", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(0, 10);
}
});
}
protected void moveParty(int xDelta, int yDelta) {
partyPoint.x += xDelta;
partyPoint.y += yDelta;
Point view = fromWorld(partyPoint);
if (view.x > getWidth() - (party.getWidth() / 2)) {
viewPort.x += xDelta;
if (viewPort.x + getWidth() > map.getWidth()) {
viewPort.x = map.getWidth() - getWidth();
partyPoint.x = map.getWidth() - (party.getWidth() / 2) - 1;
}
invalidate();
} else if (view.x < party.getWidth() / 2) {
viewPort.x += xDelta;
if (viewPort.x < 0) {
viewPort.x = 0;
partyPoint.x = (party.getWidth() / 2);
}
invalidate();
}
System.out.println(view + "; " + getHeight());
if (view.y > getHeight() - (party.getHeight() / 2)) {
viewPort.y += yDelta;
if (viewPort.y + getHeight() > map.getHeight()) {
viewPort.y = map.getHeight() - getHeight();
partyPoint.y = map.getHeight() - (party.getHeight() / 2) - 1;
}
invalidate();
} else if (view.y < party.getHeight() / 2) {
viewPort.y += yDelta;
if (viewPort.y < 0) {
viewPort.y = 0;
partyPoint.y = (party.getHeight() / 2);
}
invalidate();
}
repaint();
}
#Override
public void invalidate() {
view = null;
super.invalidate();
}
public BufferedImage getView() {
if (view == null && getWidth() > 0 && getHeight() > 0) {
view = map.getSubimage(viewPort.x, viewPort.y, getWidth(), getHeight());
}
return view;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (map != null) {
g2d.drawImage(getView(), 0, 0, this);
Point real = fromWorld(partyPoint);
int x = real.x - (party.getWidth() / 2);
int y = real.y - (party.getHeight()/ 2);
g2d.drawImage(party, x, y, this);
}
g2d.dispose();
}
protected Point fromWorld(Point wp) {
Point p = new Point();
p.x = wp.x - viewPort.x;
p.y = wp.y - viewPort.y;
return p;
}
}
}
This is how I do in my engine.
I'll keep two variables OffSetX and OffSetY
And calculate them every step to center the player like this.
OffSetX = 0;
OffSetY = 0;
if (MAP_WIDTH > WINDOW_WIDTH) {
OffSetX = Math.round(WINDOW_WIDTH / 2 - obj.getX() - TILE_SIZE);
OffSetX = Math.min(OffSetX, 0);
OffSetX = Math.max(OffSetX, WINDOW_WIDTH - MAP_WIDTH);
}
if (MAP_HEIGHT > WINDOW_HEIGHT) {
OffSetY = Math.round(WINDOW_HEIGHT / 2 - obj.getY() - TILE_SIZE);
OffSetY = Math.min(OffSetY, 0);
OffSetY = Math.max(OffSetY, WINDOW_HEIGHT - MAP_HEIGHT);
}
And then draw the map at the position (OffSetX, OffSetY) i.e., just add these to the original position of the object to draw.
You may want to skip rendering objects which are not visible.