I am generating 100 ovals as particles in the initialization method and then I want to move them by a certain amount(lets say x) for n number of iterations. I have written the following code snippet to do that.
private void drawNParticles(Graphics g)
{
ArrayList<Integer> list;
list = new ArrayList<Integer>(Collections.nCopies(n, 0));
for(int i=0;i<list.size();i++)
{
generateParticle(g);
}
}
private void generateParticle(Graphics g)
{
int radius = 4;
ArrayList<Integer> list= new ArrayList<Integer>();
list=positionParticles(particle_x,particle_y);
g.setColor(Color.RED);
g.fillOval(list.get(0),list.get(1), radius, radius);
}
private ArrayList<Integer> positionParticles(int x, int y)
{
int radius = 4;
ArrayList<Integer> list= new ArrayList<Integer>();
if(this.particle_counter==0)
{
x=randomInteger(2,678); // bounds of x between which the particles should be generated
y=randomInteger(2,448); // bounds of y between which the particles should be generated
x=x-(radius/2);
y=y-(radius/2);
if((x<251&&x>149)&&(y<266&&y>224))
{
x=0;
y=0;
positionParticles(x,y);
}
if((x<541&&x>499)&&(y<401&&y>299))
{
x=0;
y=0;
positionParticles(x,y);
}
this.particle_counter++;
}
else
{
setXPosition_particle(x);
setYPosition_particle(y);
}
list.add(x);
list.add(y);
return list;
}
public void setXPosition_particle(int x)
{
this.particle_x=x+5;
System.out.println("Particle_X:"+this.particle_x);
}
public void setYPosition_particle(int y)
{
particle_y=y+5;
System.out.println("Particle_Y:"+this.particle_y);
}
What I want is that each particle's position should be incremented by 5. But in the output, every particle gets the same value. I am getting a diagonal line across my JPanel. What should I do to access each instance variable separately?
Why don't you just create a Particule class and maintain a List<Particule> ?
Your first for loop is messing up as is the generateParticle method. You should pass the index, i, into the method, you should not create a new and completely unrelated ArrayList inside the generateParticle method but instead use the ArrayList class field, list, inside of the method.
I also recommend that you not use the paint or paintComponent method to move your particles as you do not have full control over when or if it is called. Instead separate the moving of particles and their drawing by doing the moving say in a Swing Timer, and then simply iterating through the List in the paintComponent method, drawing each point.
Related
I am working on a 2D platformer game for my, last, HS year project.
The game is basically about a player walking back & forward, collecting points and reaching goals... The player can shoot bullets and when bullets hit a block, it is destroyed. Now, I wanted to add an explosion effect using so called "particle" objects. I have written the manager class for it and it seemed to have worked the first time but after shooting a few times, i noticed that the particles stopped getting deleted, they just continue and travel out of screen. The life-time limit is 500ns.
I have also noticed that if i shoot bullets as soon as the game starts, the effect finishes as it is supposed to. but after waiting for a few more seconds and then shooting bullets, the effect particles do not behave as they should.
Here is what it looks like when i shoot bullets as soon as i start the game (What it's supposed to look like):
and here is what it looks like, after waiting a few seconds before shooting the bullets.
ParticleManager.java
public class ParticleManager {
private ArrayList<Particle> particles;
private ArrayList<Particle> removeParticles;
public ParticleManager() {
particles = new ArrayList<Particle>();
removeParticles = new ArrayList<Particle>();
}
public int getListSize() {
return particles.size();
}
/*
Generate particles
*/
public void genParticle(int x, int y, int amount) {
for(int i = 0; i < amount; i++) {
particles.add(new Particle("explosion" , x,y, i));
}
}
public void update() {
// Iterate trough particle objects
// update them & check for lifeTime
for(Particle p: particles) {
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
}
// finally, delete all "remove-marked" objects
particles.removeAll(removeParticles);
}
public void render(Graphics2D g) {
for(Particle p: particles) {
p.render(g);
}
}
}
Particle.java
class Particle {
private double px, py, x, y;
private int radius, angle;
public long timePassed;
String type;
public Particle(String type, double x, double y, int angle) {
this.x = x;
this.y = y;
this.radius = 0;
this.angle = angle;
this.timePassed = 0;
this.type = type; // explosion, tail
}
public void update() {
px = x + radius * Math.cos(angle);
py = y + radius * Math.sin(angle);
radius += 2;
this.timePassed = System.nanoTime();
}
public void render(Graphics2D g) {
g.setColor(Color.WHITE);
g.fillOval((int)px, (int)py, 5, 5);
}
}
I haven't figured out what I am doing wrong here, I've googled about some stuff and at one point i came across an answer mentioning that some references don't get deleted directly for some reason...
and my question is "How can I make these particles vanish after a certain amount of time has passed? - as shown in the first GIF"
I think the problem is that you are constantly overwriting timePassed.
// Updating particle object before
// checking for time lapse
p.update();
// Append outdated particles to removeParticles
// if time limit has passed
if(System.nanoTime() - p.timePassed >= Config.particleLife) {
removeParticles.add(p);
}
p.update() sets timePassed to now and then the if check checks if time passed is far from now (it will never be since it was just set).
I think you do want to set timePassed in the constructor (maybe it would be better named timeCreated).
Additionally, just a heads up, you never clear removeParticles so that list is going to grow forever until it causes the process to run out of memory.
Im doing an assignment for school. I have to create 30 randomly colured GameObjects in random locations. I have to use 2 classes, a GameObject class which contains the GameObject data, x and y co-ordinates and colour, plus the move and paint method... and a main MovingSquaresApplication which puts the GameObjects into an array and calls the paint() and move() methods... the current program compiles, runs, paints 60 squares (paint() and repaint()) but no animation. I've looked at a lot of different posts but still cant get it right. Any help would be great. Here is the code.....
*edited new code
import java.awt.*;
import javax.swing.*;
public class MovingSquaresApplication extends JFrame implements Runnable {
//member data
private static final Dimension WindowSize = new Dimension(600,600);
private static final int NUMGAMEOBJECTS = 30;
private GameObject[] gameObjectsArray = new GameObject[NUMGAMEOBJECTS];
private int i,j;
//constructor
public MovingSquaresApplication(){
this.setTitle("MovingSquaresApplication");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window, centered on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2;
int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
for (i=0; i<gameObjectsArray.length; i++){ //fills array with GameObjects
GameObject NewSquare = new GameObject();
gameObjectsArray[i] = NewSquare;
}
Thread t = new Thread(this); //creates and stars a thread
t.start();
}
//threads entry point
public void run(){
while (true){
try {
Thread.sleep(20);
for (j=0; j<gameObjectsArray.length; j++){
gameObjectsArray[j].move();
repaint();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//applications paint method
public void paint (Graphics g){
super.paintComponents(g);
for (i=0; i<gameObjectsArray.length; i++){
gameObjectsArray[i].paint(g);
}
}
//applications entry point
public static void main(String[] args){
MovingSquaresApplication w = new MovingSquaresApplication();
}
}
and the GameObject class
import java.awt.*;
public class GameObject {
//member data
private int x,y,xvel=2,yvel=2;
private Color c;
public GameObject(){
x = (int) (Math.random( )*600);
y = (int) (Math.random( )*600);
int R = (int) (Math.random( )*256);
int G = (int)(Math.random( )*256);
int B= (int)(Math.random( )*256);
c = new Color (R, G, B);
}
//public interface
public void move(){
x += xvel;
y += yvel;
if(x<10)
{
xvel = 2;
}
else if(y<30)
{
yvel = 2;
}
else if(x>=560)
{
xvel = -2;
}
else if(y>=560)
{
yvel = -2;
}
}
public void paint(Graphics g){
g.setColor(c);
g.fillRect(x, y, 30, 30);
}
}
Thanks for all the help, much appreciated
Thanks for the help, I didnt create a class that extends JPanel, i simply put
super.paintComponent(g);
in the paint method, not sure if thats good practice but it worked....also on a sidenote i haven't seen this before
for (GameObject gameObject : gameObjectArray)
what exactly does this do compared to the loop i've used?
You need to paint within the paintComponent method of a JPanel (as I'm sure that you've read,.... and so I recommend that you do just that. That you
Fill your GameObjectsArray with GameObjects, and do so not within any painting method, but on GUI construction
Create a JPanel and override its paintComponent method just as the Swing painting tutorials tell you to do
Call the super's paintComponent method within your override (again as the tutorials will tell you to do)
iterate through your GameObjectsArray (but rename it gameObjectsArray since its a variable not a class) within the paintComponent method
call each GameObject's paint method within that same for loop.
edit: check out this code of yours:
GameObject MoveSquare = new GameObject();
for (y = 0; y < GameObjectsArray.length; y++) {
MoveSquare.move();
}
What you're doing is creating a completely new GameObject object, MoveSquare, and are trying to move it within the for loop, meanwhile you're not touching any of the GameObjects held within the gameObjectsArray. Do you see your mistake here?
Edit 2
Also you're using the y variable as the array index, the same variable that you're using to figure out the y-axis bounds of your GUI -- don't do this. Use a completely independent variable.
Edit 4
And here:
public void paint(Graphics g) {
for (y = 0; y < GameObjectsArray.length; y++) {
GameObject NewSquare = new GameObject();
if (GameObjectsArray[y] == null) {
GameObjectsArray[y] = NewSquare;
NewSquare.paint(g);
}
}
}
You're creating new GameObject variables with each call to paint, ignoring any that already may be present in the array(??). Painting methods should be for painting and painting only. Again, fill your GameObject array with new GameObject items once and in your class constructor, not in a painting method.
You're doing a lot of guessing here, and throwing code at the wall and seeing what sticks is not a good heuristic for creating a program. Instead plan each step on paper before committing code to IDE.
Edit 5
Your if conditions within the GameObject move method need to be fixed. But once you get the code running, you'll see exactly what I mean, as you'll see all your GameObjects running off of the page.
Edit 6
I'm not going to show you all your code, but again, you'll want to create a class that extends JPanel, override its paintComponent method, and that method will be quite simple and look like this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // do housekeeping painting
// note that I've renamed the array to gameObjectArray
for (GameObject gameObject : gameObjectArray) {
gameObject.paint(g); // this is all you need to call
}
}
Likewise, the run method would be something like:
#Override
public void run() {
while (true) {
try {
Thread.sleep(SLEEP_TIME); // constant for the sleep time
} catch (InterruptedException e) {
e.printStackTrace();
}
// again note that the array has been renamed
for (GameObject gameObject : gameObjectArray) {
gameObject.move(); // this is all that needs to be called here
}
repaint();
}
}
Edit next :)
You're creating two Thread objects and starting them both -- don't do that. Only one will do.
What I'm trying to accomplish is adding 1 to the all the numbers in shipX array list, question is, how? I want to do this when the method move() is called, but how would I make this happen, as I'm new with arrays
class Ship
{
public void paint(Graphics g)
{
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
}
}
To start, you will have to move your arrays for points outside the local scope of paint() and into the class so that move() has access to the current values. You would increment in the move() method and call whatever routine you use to redraw your component.
class Ship
{
//make your polygon points members of the class
//so that you can have state that changes
//instead of declaring them in the paint method
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
//set these to the amount you want per update. They can even be negative
int velocityX = 1;
int velocityY = 1;
public void paint(Graphics g)
{
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
//add 1 to each value in shipX
for (int i=0; i<shipX.length; i++)
{
shipX[i] += velocityX;
}
//add 1 to each value in shipY
for (int i=0; i<shipY.length;i++)
{
shipY[i] += velocityY;
}
//call whatever you use to force a repaint
//normally I would assume your class extended
//javax.swing.JComponent, but you don't show it in your code
//if so, just uncomment:
//this.repaint();
}
}
Although I should point out that the repaint() method on JComponent does need to be called from the correct Swing thread, as pointed out in this answer.
If you are also trying to animate the movement, you can check out the Java Tutorial on Swing timers to call your move() method on a schedule. You could also use an ActionListener on a button to either control the Timer or on a button to move the object manually once per click.
All you have to do is iterate through the array and modify the value of each index:
for (int i = 0; i < shipX.length; i++)
{
shipX[i]++;
}
Increase the numbers one by one...
for (i=0; i<shipX.length; i++)
{
shipX[i]++; // same as shipX[i] = shipX[i] +1
}
for (i=0; i<shipY.length;i++)
{
shipY[i]++;
}
I am currently working on a space invaders style game but I have run into a bit of trouble with multiple instances of bullets. At the moment I can only fire one. I have been trying to get it to work with an Array List but I just can't seem to get it to work. The closest I got I got it to working was, it fired multiple bullets but they all spawned from the same location as in the bullets didn't spawn in relation to the ships position. The game also crashed when I removed an object after it exceeded it's boundary. Can anyone help me to see where I am going wrong. Here is some code that I have so far the parts commented out are my attempts at getting the array list to work
import java.util.ArrayList;
import org.newdawn.slick.Input;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.GameContainer;
public class Player extends Entity
{
private int speed = 5;
private ArrayList<Bullet> bulletList;
private boolean firing;
private Bullet bullet;
public Player()
{
bullet = new Bullet();
//bulletList = new ArrayList<Bullet>();
this.setImage("ship");
this.setPosition(350,450);
this.setDimenseions(100, 100);
this.createRectangle();
}
#Override
public void entityLogic(GameContainer gc, int deltaTime)
{
Input input = gc.getInput();
if(input.isKeyDown(Input.KEY_A))
{
this.x -= speed;
}
if(input.isKeyDown(Input.KEY_D))
{
this.x += speed;
}
if(input.isKeyDown(Input.KEY_W))
{
this.y -= speed;
}
if(input.isKeyDown(Input.KEY_S))
{
this.y += speed;
}
if(input.isKeyPressed(Input.KEY_SPACE))
{
firing = true;
bullet.x = this.getX()+40;
//BulletList.add(new Bullet());
}
if(firing)
{
/*Carries out the logic for the bullet*/
//for(Bullet b : bulletList)
//{
//b.entityLogic(gc, deltaTime);
//}
//Moves the bullet negativly along the y axis
bullet.entityLogic(gc, deltaTime);
}
}
#Override
public void entityRendering(Graphics g)
{
g.drawImage(this.getImage(), this.getX(), this.getY());
if(firing)
{
/*Draws each bullet object in the list*/
//for(Bullet b : bulletList)
//{
//b.entityRendering(g);
//}
bullet.entityRendering(g);
}
}
}
First of all forget about your Bullet bullet instance variable. You don't need it, the list is enough.
Another thing is that you could use a LinkedList instead that an ArrayList because you don't need random access and you have to add and remove items frequently, when you iterate over bullets to check for collision use a ListIterator<T> and remove them on the fly.
Finally it should be something like:
List<Bullet> bullets = new ArrayList<Bullet>();
public void entityLogic(GameContainer gc, int deltaTime) {
// since this method is called many times you should shoot a bullet just every X msec
if (spacebar pressed) {
// you spawn a new bullet according to player position
Bullet bullet = new Bullet(player.x,player.y);
// you add it to the list
bullets.add(bullet);
}
// destroy bullets which are outside the viewport
for (int i = 0; i < bullets.size(); ++i) {
Bullet bullet = bullets.get(i);
if (bullet.isOutsideBounds()) {
bullets.remove(i);
i--;
}
}
public void entityRendering(Graphics g) {
for (Bullet bullet : bullets)
bullets.entityRenering(g);
}
}
This is just to give you the basic idea.
I don't know slick2d and how it manages the rendering and logic threads, if they are two different threads then you should use a syncronized list, eg:
List<Bullet> bullets = Collections.synchronizedList(new ArrayList<Bullet>());
I'm working on making a board game for chess and checkers (and a few variations that I want to make). I've got a Board class that extends JPanel and sets up a doubly dimensioned array of JPanels to act as my board. Here's some of the code for my board class:
public class Board extends JPanel {
private static final int COLS = 8;
private static final int ROWS = 8;
private JPanel[][] board = new JPanel[COLS][ROWS];
private JPanel chessBoard;
public Board() {
super();
super.setLayout(new BorderLayout());
chessBoard = new JPanel();
chessBoard.setLayout(new GridLayout(COLS,ROWS));
// Set up JPanels on bottom and right to display letters and numbers for the board
// JPanels are called south and west
super.add(chessBoard, BorderLayout.CENTER);
super.add(south, BorderLayout.SOUTH);
super.add(west, BorderLayout.WEST);
for (int i=0; i<COLS; i++) {
for (int j=0; j<ROWS; j++) {
// Set up the grid
board[i][j] = new JPanel();
board[i][j].setBackground(getColor(i,j));
chessBoard.add(board[i][j]);
}
}
super.validate();
}
private Color getColor(int x, int y) {
if ((x + y) % 2 == 0) {
return Constants.GOLD;
} else {
return Constants.PURPLE;
}
}
public void addPiece(Piece piece) {
JLabel p = piece.getImage();
board[piece.getX()][piece.getY()].add(p);
chessBoard.validate();
}
}
Piece is an interface that that I'm going to use for all my pieces. I've set up the interface and set up one class that implements the interface (Checker class). I have all of that set up. The pieces are JLabels with ImageIcons in them. The only problem I'm having so far is writing a move method. I can figure out the logic make sure a move is a valid one, I just don't know how to actually make the move happen.
EDIT: I'm not even asking about mouse listeners or anything like that, I just want some pseudocode to explain making a piece move from one spot in the array to another.
EDIT 2: Here's the code for my Checkers class.
public class Checker implements Piece {
private int side,xPos,yPos;
private JLabel img;
public Checker(int team, int x, int y) {
BufferedImage image;
try {
if (team == 0)
image = ImageIO.read(new File("img/RedPiece.png"));
else
image = ImageIO.read(new File("img/BlackPiece.png"));
} catch(IOException e) {
image = null;
System.out.printf("Image file wasn't found!!!");
System.exit(1);
}
img = new JLabel(new ImageIcon(image), SwingConstants.CENTER);
img.setVerticalAlignment(SwingConstants.CENTER);
xPos = x;
yPos = y;
}
// TODO Figure out move method
public void move(int dx, int dy) {
}
// Also typical gets and sets for instance variables
So my thought is I call the move method for a checkers piece and, assuming I'm moving from the bottom of the screen to the top it would be piece.move(-1,1); and I have to remove the piece from it's current position, then it's new position in the array is [x + dx][y + dy]
Can you use something like this:
public void movePiece(Piece piece, int dx, int dy) {
// Save current position, so we can erase the piece.
int oldX = piece.getX();
int oldY = piece.getY();
// Update the location.
piece.setX(oldX + dx);
piece.setY(oldY + dy);
// Remove piece from old position
board[oldX][oldY].clear();
// Add it to the new position.
addPiece(piece);
}
You'd probably want to use a Point instead of individual x and y coordinates; I just thought this would be easier to understand.
By moving a Piece, you are going to change at least 2 elements of the 2-dimensional array board[][], which is inside your Board class. It's better to implement the method in the Board class, since Piece can only make change to it self. If you put move() in Piece class, and a Piece need to change another Piece, it needs to talk to the Board and ask the Board to pass the reference of the other Piece to it. What are you going to change about each Piece is totally depends on your design, such as colour, picture. Here is my suggestion:
Board:
move(Piece from, Piece to){
... // validation
from.remove();
to.put(team);
// over is the one you jump over, optional, some if statements here
Piece over = Board.getOver(Piece from, Piece to);
over.remove();
// check for further move is also optional
if(board.isFurthermoveAvailable(to)){
from = to;
to = board.getFurthermoveLocation(from);
board.move(from, to);
}
}
getOver(Piece from, Piece to){
return board[(from.getX()+to.getX())/2][(from.getY()+to.getY())/2];
}
isFurthermoveAvailable(Piece from){
int team = from.getTeam();
... // your logic
}
// depends on what you return by isFurthermoveAvailable(Piece from)
// if you return boolean, then you also need the method below
// or, you can let the above method return null or a Piece
getFurthermoveLocation(Piece from){
... // your logic
}
Piece:
remove(){
... // changes such as the picture, colour
}
put(int Team){ // this method is obviously depends on team
...
}
// other methods may assist to the process
getTeam(){
}
getX(){
}
getY(){
}