I am recreating the game space invaders and have reached the point of firing a projectile. I've been using the KeyListener class successfully so that when the spacebar is pressed my projectile fires. The issue is that it only updates it's position after it has been fired, so it fires from the position that laser canon was last placed not its current position.
My laserCanon class
/*
*The properties and behaviors of the laser canon
*/
package spaceinvaders;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Polygon;
public class LaserCanon extends GameObject{
private int pnlWidth;//GamePanel width
private int pnlHeight;//GamePanel height
private final int moveInc = 15;//number of pixels moved when when arrow key is pressed
//Constructor
public LaserCanon(int pnlWidth, int pnlHeight){
super();
this.pnlWidth = pnlWidth;
this.pnlHeight = pnlHeight;
getLocation().x=pnlWidth;//sets initial location of canon
getLocation().y=pnlHeight;//sets intial location of canon
setColor(Color.green);//canon is green
setVisible(true);
}
public LaserCanon(){
super();
}
//draws laser canon using GamePanel height and width
#Override
public void draw(Graphics g){
g.setColor(this.getColor());
Polygon triangle = new Polygon();//canon is in shape of triangle
triangle.addPoint(getLocation().x, getLocation().y);//bottom right point
triangle.addPoint(getLocation().x-100, getLocation().y);//bottom right point
triangle.addPoint(getLocation().x-50, getLocation().y-75);//top point
g.fillPolygon(triangle);
}
//returns each property in a string
#Override
public String toString(){
String string = super.toString();
string = getPnlWidth() + "|" + getPnlHeight() + "|" + getMoveInc();
return string;
}
//moves canon left
public void moveLeft(){
if(getLocation().getX()>50){
System.out.println("Left key pressed\n" + getLocation().getX());
getLocation().x-=moveInc;
}
}
//moves canon right
public void moveRight(){
if(getLocation().getX()<pnlWidth){
System.out.println("Right key pressed\n" + getLocation().getX());
getLocation().x+=moveInc;
}
}
//accessor and mutator methods
My Projectile Class
public class Projectile extends GameObject{
private int speed;//speed at which the projectile moves
private int locX;
private int locY;
private GamePanel gamePanel;
//constructor
public Projectile(int speed, GamePanel gp){
super();
this.speed = speed;
gamePanel = gp;
//sets location of projectile to same location as canon Starting at top point
this.locX = gamePanel.getLaserCanon().getLocation().x-50;
this.locY = gamePanel.getLaserCanon().getLocation().y-75;
setColor(Color.cyan);//projectile is cyan
setVisible(false);//not visible to start
}
public Projectile(){
super();
}
#Override
public void draw(Graphics g){
if(isVisible())
g.setColor(this.getColor());
else
g.setColor(Color.black);
Polygon triangle1 = new Polygon();
triangle1.addPoint(getLocX()-5, getLocY());//bottom left point
triangle1.addPoint(getLocX()+5, getLocY());//bottom right point
triangle1.addPoint(getLocX(), getLocY()-15);//top middle point
Polygon triangle2 = new Polygon();
triangle2.addPoint(getLocX(), getLocY()+3);//bottom middle point
triangle2.addPoint(getLocX()-5, getLocY()-10);//bottom left point
triangle2.addPoint(getLocX()+5, getLocY()-10);//bottom right point
g.fillPolygon(triangle1);
g.fillPolygon(triangle2);
}
public int move(){
setLocY(getLocY() - getSpeed());
return getLocY();
}
//accessor and mutators
And my game panel class to hold each of the former:
package spaceinvaders;
import java.awt.Color;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
import java.util.ArrayList;
import javax.swing.Timer;
import javax.swing.BorderFactory;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class GamePanel extends JPanel implements KeyListener{();
private LaserCanon laserCanon;
private Projectile projectile;
private Timer projectileTimer;//used to animate the projectile fired from LaserCanon
//constructor
public GamePanel(){
setSize(800,800);//size of panel
setBackground(Color.BLACK);//background
setBorder(BorderFactory.createLineBorder(Color.red, 3));//border
laserCanon = new LaserCanon(getWidth(), getHeight());
projectile = new Projectile(20,this);
projectileTimer = new Timer(50, new TimerListener());
//instantiate other GameObjects
//gives focus to this panel for KeyListener
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
repaint();
}
#Override
public void keyPressed(KeyEvent k){
int key = k.getKeyCode();
if(key == k.VK_LEFT){//if left arrow is pressed
getLaserCanon().moveLeft();
repaint();
}
else if(key == k.VK_RIGHT){//if right arrow is pressed
getLaserCanon().moveRight();
repaint();
}
else if(key == k.VK_SPACE){
System.out.println("fired!");
getProjectile().setVisible(true);
getProjectileTimer().start();
}
}
#Override
public void keyReleased(KeyEvent k){
//dummy method
}
#Override
public void keyTyped(KeyEvent k){
//dummy method
}
private class TimerListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e){
if(getProjectile().move()>-15){
repaint();
}
else{
getProjectileTimer().stop();
getProjectile().setVisible(false);
projectile.setLocX(laserCanon.getLocation().x-50);
projectile.setLocY(laserCanon.getLocation().y-75);
repaint();
}
}
}
//used to call draw methods
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
getLaserCanon().draw(g);
getProjectile().draw(g);
}
After placing
projectile.setLocX(laserCanon.getLocation().x-50);
projectile.setLocY(laserCanon.getLocation().y-75);
in my TimerListener class after it has detected that the projectile is no longer on screen I realized that I need another set of these methods somewhere else and have been playing around with it, but I can't seem to figure out where. Anywhere else I place them solves the position problem, but I lose the animation.
Basically, where ever my laser canon goes I need my projectile to follow and fire from the laser canon's position. How can I get that to happen?
Side note: There is an abstract class GameObject that holds the visibility, location (using the Point class), and color of my projectile and laser canon.
I found that by adding in a moveLeft() and moveRight() methods like those that are in my LaserCanon class, to my projectile class it would move with the canon rather than depending on the cannon to move.
Related
So I am creating a brick breaker game. I got the paddle moving using key listeners, however I got some advice to use key bindings instead. I've been reading and looking everywhere on this and I think I've kinda got the idea but the implementation is confusing me a bit.
For my paddle, I created it with the paint component. Hence this is what I want to be able to move left and right with the arrow keys. However, all the key bindings explanations I find seem to use JComponent which the paddle is not. Is there a way around it or will I have to make my paddle a JComponent image icon instead? If so would I just load the image into my Paddle class?
Also what's the best way of structuring my code to contain the key bindings? For instance am I better off creating a whole new class for it, or putting it in e.g. my GamePanel class
Any tips?
Here is some of my code so you can get an idea:
Main Class:
public class BrickBreakerGameApp {
public static void main(String[] args) {
int pw = 500;
int ph = 900;
GamePanel gPanel = new GamePanel(pw,ph);
GameFrame gFrame = new GameFrame();
gFrame.getContentPane().add(gPanel); //add game panel to frame
// gFrame.addKeyListener(gPanel); //adds the key listener for the game panel frame
gFrame.pack();
gFrame.setVisible(true); //make frame visible
}
}
GameFrame class:
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
//Global Variables
public int frameWidth = 500;
public int frameHeight = 800;
//create constructor
GameFrame () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //so app closes properly
this.setPreferredSize(new Dimension(frameWidth, frameHeight)); //set frame size
this.setTitle("Brick Breaker Game");
ImageIcon icon = new ImageIcon("res/brick-breaker-logo.jpg"); //create image icon
this.setIconImage(icon.getImage()); //update frame icon
this.pack();
}
}
GamePanel Class
import java.awt.Color;
import java.awt.event.*;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.*;
/**
* This class handles the game panel as a whole
*/
public class GamePanel extends JPanel {
// Global Variables
private Ball ball;
private Paddle paddle;
private Bricks bricks;
private GameFrame gameFrame;
private int width;
private int height;
private int[] bArray = new int[20];
// create a constructor
GamePanel (int gamePanelWidth, int gamePanelHeight) {
this.setWidth(gamePanelWidth);
this.setHeight(gamePanelHeight);
initialiseGame();
this.isVisible();
}
private void initialiseGame() {
ball = new Ball(10, 520, 30, 30); //create the ball object
paddle = new Paddle(this, 50, 700, 100, 10); //creates paddle object
bricks = new Bricks(10, 10, 60, 30, bArray); //creates the bricks object
//for key binding initialisation
MotionAction motion = new MotionAction(paddle, 24);
}
// paint all the elements in
public void paintComponent(Graphics g) {
super.paintComponent(g);
// background
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// paddle
// g.setColor(Color.CYAN);
// g.fillRect(paddle.getPaddleX(), paddle.getPaddleY(), paddle.getPaddleWidth(), paddle.getPaddleHeight());
// ball
g.setColor(Color.MAGENTA);
g.fillOval(ball.getBallX(), ball.getBallY(), ball.getBallWidth(), ball.getBallHeight());
// brick
g.setColor(Color.GREEN);
g.fillRect(bricks.getBrickX(), bricks.getBrickY(), bricks.getBrickWidth(), bricks.getBrickHeight());
}
//add any unimplemented methods because we are using an interface
/* #Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
paddle.moveLeft();
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
paddle.moveRight();
}
this.repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
} */
//create get and set methods for all panel attributes
public int getWidth() {
return width;
}
public void setWidth(int pWidth) {
this.width = pWidth;
}
public int getHeight() {
return height;
}
public void setHeight(int pHeight) {
this.height = pHeight;
}
}
Paddle class:
import javax.swing.AbstractAction;
import java.awt.event.*;
public class Paddle extends AbstractAction implements ActionListener {
//Global Variables
private int paddleWidth;
private int paddleHeight;
private int paddleX; //paddle x position
private int paddleY;
private GamePanel gamePanel;
//create paddle constructor
Paddle() {
}
//create a paddle constructor based off parameters
Paddle(GamePanel gPanel, int pX, int pY, int pWidth, int pHeight) {
//set the values
this.setPaddleWidth(pWidth);
this.setPaddleHeight(pHeight);
this.setPaddleX(pX);
this.setPaddleY(pY);
this.setGamePanel(gPanel);
}
//create get and set methods for all paddle attributes
public int getPaddleWidth() {
return paddleWidth;
}
public void setPaddleWidth(int pWidth) {
this.paddleWidth = pWidth;
}
public int getPaddleHeight() {
return paddleHeight;
}
public void setPaddleHeight(int pHeight) {
this.paddleHeight = pHeight;
}
public int getPaddleX() {
return paddleX;
}
public void setPaddleX(int pX) {
this.paddleX = pX;
}
public int getPaddleY() {
return paddleY;
}
public void setPaddleY(int pY) {
this.paddleY = pY;
}
public GamePanel getGamePanel() {
return gamePanel;
}
public void setGamePanel(GamePanel gPanel) {
this.gamePanel = gPanel;
}
//move the paddle left if it is not already positoned at 0 (far left)
public void moveLeft() {
try {
if(getPaddleX() <= 0) {
setPaddleX(0);
System.out.println("less than 0, x: " + getPaddleX());
}
else if (getPaddleX() > 0) {
setPaddleX(getPaddleX()-10); //to move paddle left -10
// gamePanel.repaint(getPaddleX()+10, getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint old position
// gamePanel.repaint(getPaddleX(), getPaddleY(), getPaddleWidth(), getPaddleHeight()); //repaint new position
System.out.println("left, x: " + getPaddleX());
}
}
catch (Exception e) {
}
}
//move the paddle right if it is not already positioned to the far right of the panel
public void moveRight() {
if(getPaddleX() >= gamePanel.getWidth() - getPaddleWidth()) { //dont move the paddle if it is on the right edge of the panel
setPaddleX(gamePanel.getWidth() - getPaddleWidth());
System.out.println("right1, x:" + getPaddleX());
}
else if ((getPaddleX()+getPaddleWidth()) <= gamePanel.getWidth()){ //if the paddle is within the panel bounds
setPaddleX(getPaddleX() + 10); //to move paddle right +10
System.out.println("right, x:" + getPaddleX());
}
}
}
Here are some of the main resources I've being trying:
This one I tried but got really confused on the best way to integrate it into my own code --> https://tips4java.wordpress.com/2013/06/09/motion-using-the-keyboard/
This one I tried until I realised I don't have jcomponent --> https://coderanch.com/t/606742/java/key-bindings
You could register the key bindings with the GamePanel, or the frame content pane (both extend from JComponent). E.g.:
public class DemoFrame extends JFrame {
public static void main(String[] args) throws Exception {
new DemoFrame().setVisible(true);
}
public DemoFrame() {
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
{
String actionId = "left";
KeyStroke keyStroke = KeyStroke.getKeyStroke("LEFT");
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, actionId);
getRootPane().getActionMap().put(actionId, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
actionLeft();
}
});
}
}
private void actionLeft() {
System.out.println("left");
}
}
INTRODUCTION
Hi guys, I was learning how to make a little game where you are a racquet (rectangle) and all the asteroids (enemies) are falling down the screen and you have to avoid them
PROBLEM
When the game starts the enemies (asteroids) are paint on the screen in a very high speed, and they occupy all the size of the screen so there is no way to avoid them (try the game), I just want that between painting an enemy and the next one there is a mininum time to delay (for example 0,5 seconds).
But I just don't know how to do that, I tried to use Thread.sleep() and TimeUnit but they just make the game slower.
Surfing on stackoverflow I've find out that I may try to use Swing timers, I've read some stuff on the web but I want to know how can I use swing timers in my code (if they can solve my problem).
Here it is the code:
The main class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class Game extends JPanel {
Racquet racquet = new Racquet(this);
Enemy Enemy = new Enemy(this);
static ArrayList<Enemy> enemyList = new ArrayList<Enemy>();
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
/** TO SET THE RANDOM POSITION ON WHERE THE ENEMIES HAVE TO APPEAR ON THE SCREEN **/
public int random(int x, int y, ArrayList<Enemy> pa){
int r = 0;
for(int i = 0; i<pa.size(); i++){
Random rand = new Random();
r = rand.nextInt(x+y)-1;
return r;
}
return r;
}
/** letting the enemies move on the screen **/
private void move() {
for(int i = 0; i < enemyList.size(); i++){
enemyList.get(i).move();
}
racquet.move();
}
/** Painting on the screen enemies and the racquet **/
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int i = 0; i < enemyList.size(); i++){
enemyList.get(i).paint(g2d);
}
racquet.paint(g2d);
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public void createEnemy(){
enemyList.add(new Enemy(this));
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Asteroids");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.random(200, 300, enemyList);
while (true) {
game.createEnemy();
game.move();
game.repaint();
Thread.sleep(5);
}
}
}
The racquet class:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 30;
private static final int HEIGHT = 6 ;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game = game;
}
/** letting the racquet moves on the screen **/
public void move() {
if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
x = x + xa;
}
/** Creating the rectangle racquet **/
public void paint(Graphics2D g) {
g.fillRect(x, Y, WIDTH, HEIGHT);
}
/** // Setting xa everytime to 0, if we don't do this it just takes a single pression to go to a direction until we press the other key **/
public void keyReleased(KeyEvent e) {
xa = 0;
}
/** Choosing the direction **/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds() {
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY() {
return Y;
}
}
And the enemy class:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.*;
public class Enemy {
private Game game;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
/** Generating a random position where the enemies have to appear **/
public Enemy(Game game){
this.game = game;
x = game.random(0, 320, game.enemyList);
}
/** Paint the enemies **/
public void paint(Graphics2D g) {
g.fillRect(x, y, 20, 20);
}
/** move the enemies and detect collisions **/
public void move(){
y += ya;
if(collision()){
game.gameOver();
}
}
/** returns true if the enemy rectangle touch the racquet **/
public boolean collision(){
return game.racquet.getBounds().intersects(getBounds());
}
public Rectangle getBounds() {
return new Rectangle(x, y, 20, 20);
}
}
Suggestions:
Your game "tick" time is 5 mSecs, a not quite reasonable time. I suggest that
You get rid of the "magic" number, using a constant instead,
and make the tic a little bigger, say 12 to 15 mSec.
Also better to use a Swing Timer or to at least make sure that you do your while loop in a defined background thread.
Most importantly, you're creating a new enemy with each tick of your game loop, and that's too fast. Instead:
Don't create a new Enemy with each tick,
Instead save the time that the last enemy was created in a field,
Check the delta-time, the current system time - lastEnemyCreationTime, inside of your game-loop,
Only create a new enemy if the delta-time is greater than a reasonable value, either a constant value or a field (not a magic number).
On creation of the new enemy, reset the lastEnemyCreationTime to the current system time.
Unrelated recs:
Override the JPanel's paintComponent, not the paint method as this will give you double buffering by default which can lead to smoother perceived graphics.
Favor using Key Bindings over a KeyListener as this will help to easily eliminate focus issues inherent with use of KeyListeners.
I'm trying to make a demo spaceship shooter. Every time i press the space bar I draw a new projectile(Image) in the paintComponent(Graphics g) method and call a moveProjectile() method. The problem is the moveProjectile() method seems to be off.
MyJPanel.java
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class MyJPanel extends JPanel implements ActionListener
{
private static final long serialVersionUID = 1L;
private Timer timer;
private Image backgroundImage;
private Image player;
private int playerX, playerY;
private int projectileX,projectileY;
private Image projectileImage;
private ArrayList<Image> projectiles = new ArrayList<Image>();
boolean flag = false;
public MyJPanel(Image backgroundImage, Image player,Image projectileImage)
{
this.backgroundImage = backgroundImage;
this.player = player;
this.projectileImage = projectileImage;
this.setLayout(null);
timer = new Timer(50, this);
timer.start();
this.addKeyListener(new KeyAdapter() // Listens for a keyboard event
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
{
flag = true;
moveProjectile();
}
repaint();
}
});
// Mouse listener
this.addMouseMotionListener(new MouseMotionListener()
{
#Override
public void mouseMoved(MouseEvent e)
{
playerX = e.getX();
playerY = e.getY();
}
#Override
public void mouseDragged(MouseEvent e)
{
}
});
hideMouseCursor();
this.setFocusable(true);
this.setVisible(true);
} // End of JPanle constructor
public void paintComponent(Graphics graphics)
{
super.paintComponent(graphics);
graphics.drawImage(backgroundImage,0,0,this.getWidth(),this.getHeight(),null); // Draw the background
graphics.drawImage(player,playerX,playerY,null); // Draw the player
if (flag)
{
projectileX = playerX + player.getWidth(null);
projectileY = playerY + player.getHeight(null) / 2 - 27;
graphics.drawImage(projectileImage,projectileX,projectileY,null);
}
}
public void moveProjectile()
{
while (projectileX < this.getWidth())
{
this.projectileX += 2;
repaint();
}
}
public void hideMouseCursor() // Hides the mouse cursor
{
//Transparent 16 x 16 pixel cursor image.
BufferedImage cursorbackgroundImgage = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
cursorbackgroundImgage, new Point(0, 0), "Blank Cursor");
// Set the blank cursor to the JPanel.
this.setCursor(blankCursor);
}
#Override
public void actionPerformed(ActionEvent actionEvent) // Without the method and the repaint() the mouse listener will not work
{
repaint();
}
public class ProjectileThread extends Thread
{
#Override
public void run()
{
projectileX = playerX + player.getWidth(null);
projectileY = playerY + player.getHeight(null) / 2;
}
}
public static void main(String[] args)
{
JFrame frame = new JFrame("A Game by me");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // Making the frame take a full screen
ImageIcon backgroundImageIcon = new ImageIcon("space_background_2.jpg");
Image backgroundImgage = backgroundImageIcon.getImage();
ImageIcon playerImageIcon = new ImageIcon("spaceship_1.png");
Image playerImage = playerImageIcon.getImage();
ImageIcon projectileIcon = new ImageIcon("spaceship_projectile_1.png");
Image projectileImage = projectileIcon.getImage();
frame.add(new MyJPanel(backgroundImgage,playerImage,projectileImage));
frame.setVisible(true);
}
} // End of MyJPanel
There some variables and methods i don't use so don't mind them please. The points to notice in the code:
if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
{
flag = true;
moveProjectile();
}
repaint();
If pressing space -> flag = true which means
if (flag)
{
projectileX = playerX + player.getWidth(null);
projectileY = playerY + player.getHeight(null) / 2 - 27;
graphics.drawImage(projectileImage,projectileX,projectileY,null);
}
Draw the projectile and move it to the right. The problem is it's never moved to the right. Instead it's following the spaceship which moves by the mouse.
Any suggestions will be very appreciated.
public class ProjectileThread extends Thread
{
public ProjectileThread(int playerX,int playerY)
{
projectileX = playerX + player.getWidth(null);
projectileY = playerY + player.getHeight(null) / 2;
}
#Override
public void run()
{
while (projectileX < getWidth())
{
projectileX += 2;
}
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE) // If pressing space - shoot
{
ProjectileThread projectileThread = new ProjectileThread(playerX,playerY);
projectileThread.start();
}
repaint();
}
Your moveProjectile method moves the projectile horizontally by adding 2 to its X coordinate
this.projectileX += 2;
However, your paint method overwrite this value with your player X coordinate:
projectileX = playerX + player.getWidth(null);
So everytime you paint your projectile, it's in the same place relative to the player. You need to draw the projectile first using the player coordinates, and then move it without resetting its X coordinate.
You have a thread that should be started when the projectile is fired. So in your handler for the space key, start the thread and pass it the player coordinate. This is your start point. Then in the run method of the thread, move the projectile and wait a bit in a loop.
while (projectileX < getWidth())
{
projectileX += 2;
}
All this does is set projectile = getWidth() + 1 (or possibly+2).
Similarly, your moveProjectile method has this:
while (projectileX < this.getWidth())
{
this.projectileX += 2;
repaint();
}
Which does the same thing. Note that the repaint() in the body of the loop essentially does nothing, since you block the event thread until the moveProjectile() method returns
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.sound.sampled.*;
import java.util.ArrayList;
public class Board extends JPanel implements ActionListener
{
Timer time;
Image Border;
Image Dude;
Image Road;
Image GZombie;
Image RZombie;
Image BZombie;
MovingPiece player;
public Board()
{
//set this window to be the one receiving keystrokes
addKeyListener(new AL());
setFocusable(true);
ImageIcon dude = new ImageIcon("Dude.png"); //player
Dude=dude.getImage();
// Cx and Cy are changed in move methods, they are change in (x/y)
// X Y W H CxCy Speed Image
player=new MovingPiece(200,300,50,50,0,0,2,Dude);
time=new Timer(5,this);
time.start();
}
public void actionPerformed(ActionEvent e){
player.setX(player.getX() + player.getCx()); //adds my x to my change in x
player.setY(player.getY() + player.getCy()); //im sure u can figure this one out...
//redraw the screen
repaint();
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(player.getImage(),player.getX(),player.getY(),null); //draw player
}
//the key listener, it is a private class inside of the Board class
private class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
System.out.println(key); //*THIS IS WHAT WONT RUN*
if(key==KeyEvent.VK_W){player.moveUp();} //this changes my cy to be -speed which is -2
if(key==KeyEvent.VK_A){player.moveDown();} //this changes my cy to be speed which is 2
if(key==KeyEvent.VK_S){player.moveLeft();} //I made this simple.. this is cx
if(key==KeyEvent.VK_D){player.moveRight();} //take a guess.
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
if(key==KeyEvent.VK_W){player.setCy(0);} //stops my changes in y so I don't move up/down
if(key==KeyEvent.VK_A){player.setCx(0);} //quite repetitive.
if(key==KeyEvent.VK_S){player.setCy(0);}
if(key==KeyEvent.VK_D){player.setCx(0);}
}
}
}
Basically my keyadapter wont run. The print of what key is, is not important.
But it is an indicator to see if the method is running, or if the problem was with my move methods.
well since it isn't printing, then the method itself is not running. and thus it is not my move methods. it must be this adapter. I just want to know why it isn't working. I have set focusable which is all the other forums say to do. so. please help. thanks in advance
im making a side scroller and i dont know how to side scroll and im trying to scroll on the x and y axis
this is for a school project so i would like help as soon as possable
heres some of my code if you have question just ask. any advice is welcome.
source code http://www.mediafire.com/?fi1f9lv6qc2t5d7
gameCanvas.java
package Game;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
#SuppressWarnings("serial")
public abstract class GameCanvas extends Canvas implements Runnable,KeyListener{
public static final long ONE_SECOND_MILI = 1000;
protected int frameW;
protected int frameH;
protected long fps;
private long period = 15;
private BufferStrategy buff;
private Graphics graph;
private Color bckGround=(Color.GRAY);
private Image bckGround_img;
private Thread t;
boolean left;
boolean right;
boolean up;
boolean down;
int lastpressed;
int newlastpressed;
private String drawFps = "0";
public GameCanvas(int w,int h){
this.frameW=w;
this.frameH=h;
this.setIgnoreRepaint(true);
this.setBounds(0,0,frameW,frameH);
this.setBackground(Color.GREEN);
this.setVisible(true);
}
public GameCanvas(int w,int h,Color bck){
this.frameW=w;
this.frameH=h;
this.bckGround=bck;
this.setIgnoreRepaint(true);
this.setBounds(0,0,frameW,frameH);
this.setBackground(bckGround);
this.setVisible(true);
}
public void addNotify(){
super.addNotify();
this.createBufferStrategy(2);
this.buff=this.getBufferStrategy();
requestFocus();
startGame();
}
public void startGame(){
if (t==null){
t=new Thread(this);
t.start();
}
}
public void run(){
while(true){
long beginTime=System.currentTimeMillis();
// try {
// Thread.sleep(25);
// } catch (InterruptedException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
Update();
Render();
Draw();
fps=System.currentTimeMillis() - beginTime ;
long sleepTime=period-fps;
if (sleepTime == 30) sleepTime = -1;
fps= ONE_SECOND_MILI / ((period * 2) - sleepTime);
try{
if (sleepTime > 0){
Thread.sleep(sleepTime);
}
}
catch(Exception e){
}
}
}
public void Render(){
graph = buff.getDrawGraphics();
if (!HasImgBackground()){
graph.setColor(bckGround);
graph.fillRect(0, 0, frameW, frameH);
}else{
graph.drawImage(bckGround_img, 0, 0, frameW, frameH,null);
}
graph.setColor(new Color(255,255,255));
graph.drawString("FPS: " + fps , 10, 15);
Paint(graph);
}
private void Draw(){
if(!buff.contentsLost()){
buff.show();
if(graph != null){
graph.dispose();
}
}
}
private boolean HasImgBackground(){
if (bckGround_img==null){
return false;
}
return true;
}
public void setBackgroundImg(Image image){
this.bckGround_img=image;
}
public void deleteBackground(){
this.bckGround_img=null;
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_LEFT){
left=true;
if(lastpressed!=4)
newlastpressed=lastpressed;
lastpressed=4;
}
if(e.getKeyCode()==KeyEvent.VK_UP){
up=true;
if(lastpressed!=1)
newlastpressed=lastpressed;
lastpressed=1;
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
right=true;
if(lastpressed!=2)
newlastpressed=lastpressed;
lastpressed=2;
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){
down=true;
if(lastpressed!=3)
newlastpressed=lastpressed;
lastpressed=3;
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_LEFT){
left=false;
if(up||right||down)
if(newlastpressed!=0)
lastpressed=newlastpressed;
}
if(e.getKeyCode()==KeyEvent.VK_UP){
up=false;
if(left||right||down)
if(newlastpressed!=0)
lastpressed=newlastpressed;
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
right=false;
if(up||left||down)
if(newlastpressed!=0)
lastpressed=newlastpressed;
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){
down=false;
if(up||right||left)
if(newlastpressed!=0)
lastpressed=newlastpressed;
}
}
public void keyTyped(KeyEvent e) {
}
abstract void Update();
abstract void Paint(Graphics g);
}
main.java
package Game;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.JFrame;
public class Mainth extends GameCanvas{
private long timeDown = 0;
// private StopWatch t = new StopWatch();
static Collision coll=new Collision();
Character character=new Character();
static Image wallImage=ImageLoader.getImg().getImage("data/images/objects/brick_wall.png");
static Image bushImage=ImageLoader.getImg().getImage("data/images/objects/hedge_ver.png");
static ArrayList<Image> wallArray=new ArrayList<Image>();
static ArrayList<Image> wall2Array=new ArrayList<Image>();
static Sprite wallSprite;
static Sprite wall2Sprite;
static IndexCounter devIndex;
static Dude dev;
static Wall wall;
static Wall bush;
static Wall wall2;
/**not used*/
int x=0,y=0;
static ArrayList objects=new ArrayList<Entity>();
static ArrayList chars=new ArrayList<Dude>();
static ArrayList projectiles=new ArrayList<>();
public static void main(String[] args){
Mainth Canvas=new Mainth(1500,1000);
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(Canvas);
frame.pack();
frame.setSize(750, 400);
frame.setVisible(true);
Mainth.chars.add(dev);
Mainth.objects.add(wall);
Mainth.objects.add(bush);
Mainth.objects.add(wall2);
}
public Mainth(int w,int h){
super(w,h);
this.addKeyListener(this);
CharacterCreation();
}
public void CharacterCreation(){
wallArray.add(wallImage);
wall2Array.add(bushImage);
wallSprite=new Sprite(wallArray,1);
wall2Sprite=new Sprite(wall2Array,1);
dev=new Dude(character.LinkStandingDown,character.LinkStandingDown.getID(),100,300);
devIndex=new IndexCounter(character.LinkWalkingDownArray.size(),3);
wall=new Wall(wallSprite,1,100,50){};
bush=new Wall(wall2Sprite,1,185,55){};
wall2=new Wall(wallSprite,1,100,225){};
bush.setHardness(1);
}
Movement movem=new Movement();
void Update() {
movem.movement(dev, character, left, right, up, down, lastpressed, devIndex);
dev.move();
coll.objectCollision(chars,objects);
devIndex.Counter();
}
void Paint(Graphics g) {
bush.Draw(g,0);
wall.Draw(g,0);
wall2.Draw(g,0);
dev.Draw(g,devIndex.getIndex());
Graphics2D g2d= (Graphics2D) g;
}
public void animation(){
String[] animationSprites=dev.getImgs("walk_down");
int aniTime=0;
aniTime++;
}
public ArrayList<Entity> exportObjects(){
return objects;
}
public ArrayList<Dude> getMainChar(){
return chars;
}
}
What exactly isn't working in the game?
Basic side scrolling logic consists of moving the background, the characters, and the obstacles a certain increment as movement keys are held down. If the screen is "moving right," we are actually moving all of these elements to the left. If the screen is "moving left," then we are doing the opposite. Also, if an entity is moving and has a certain target point, make sure and update the coordinates of this point as you scroll, or the entity will keep moving until it reaches its original on-screen destination. You should also implement code that stops the screen from scrolling too far (thus losing the game).
There are many ways to use side-scrolling, such as scrolling when a character moves a certain distance from the center of the screen, or having controls that move the screen independently from a character (such as in an rts when one scrolls around the map). An easier way might be to always have the player be in the center of the screen, and just have the background and other entities scroll back and forth around him.
You need to coordinate systems:
world coordinates - are always constant
(local) frame coordinate - where objects should be shown in your window now
every object has only world coordinates. And you have a window in this big world. This window has its coordinates in world coordinates. To scroll the view in your window you just need to change it's world coordinates.
Of course you need a code, that renders all objects in you window for any correct position of your movable window. It can be like:
void renderFrame(Rectangle frame) {
for(GameObject go : gameObjects) {
if(frame.contains(go.getGlobalCoordinates())) {
Rectangle windowCoordinates = new Rectangle();
windowCoordinates.x = go.getGlobalCoordinates().x - frame.x;
windowCoordinates.x = go.getGlobalCoordinates().y - frame.y;
windowCoordinates.x = go.getGlobalCoordinates().width - frame.width;
windowCoordinates.x = go.getGlobalCoordinates().height - frame.height;
go.paint(g2, windowCoordinates);
}
}
}