Ok so I have been experimenting with java for a few weeks now, following both in class, and online tutorials. I made a simple game where squares fall towards the bottom of the screen, while the player controls a small ball, only moving on the x-axis and trys to avoid them.
The problem that I am having is that the squares start out falling too fast. Right now I have them set as follows:
ix = 0;
iy = 1;
Then in my move() method, I have the following:
hitbox.x += ix;
hitbox.y += iy;
In this example, ix and iy are both integers.
My first assumption was to change the ints to floats, then use:
ix= 0;
iy = 0.5;
and then:
hitbox.x += ix;
hitbox.y += 0.5f;
But this just freezes the objects in their tracks . I believe that this is because cords are taken as integers, so I figured that if I modified my getX() and getY() methods, maybe I could manipulate them somehow to use decimal numbers? But I am not quite sure how to. Any help/hints/solutions to this problem would be Greatly appreciated.
Here is some revelent code, let me know if anymore is needed!
Enemy Manager:
public class EnemyManager {
private int amount;
private List<Enemy> enemies = new ArrayList<Enemy>();
private GameInJavaOne instance;
public EnemyManager(GameInJavaOne instance, int a){
this.amount = a;
this.instance = instance;
spawn();
}
private void spawn(){
Random random = new Random();
int ss = enemies.size();
// If the current amount of enemies is less than the desired amount, we spawn more enemies.
if(ss < amount){
for(int i = 0; i < amount - ss; i++){
enemies.add(new Enemy(instance, random.nextInt(778), random.nextInt(100)+1));
}
// If its greater than the desired number of enemies, remove them.
}else if (ss > 20){
for(int i = 0; i < ss - amount; i++){
enemies.remove(i);
}
}
}
public void draw(Graphics g){
update();
for(Enemy e : enemies) e.draw(g);
}
private void update() {
boolean re = false;
for(int i = 0; i < enemies.size(); i ++){
if(enemies.get(i).isDead()){
enemies.remove(i);
re = true;
}
}
if(re) spawn();
}
public boolean isColliding(Rectangle hitbox){
boolean c =false;
for(int i = 0; i < enemies.size(); i ++){
if(hitbox.intersects(enemies.get(i).getHitbox())) c = true;
}
return c;
}
}
Entity:
public abstract class Entity {
protected int x, y, w, h;
protected boolean removed = false;
public Entity(int x, int y){
this.x = x;
this.y = y;
}
public void Draw(Graphics g){
}
public int getX() { return x; }
public int getY() { return y; }
public int getH() { return h; }
public int getW() { return w; }
}
and the enemy class:
public class Enemy extends Entity{
private Rectangle hitbox;
private int ix, iy;
private boolean dead = false;
private GameInJavaOne instance;
public Enemy(GameInJavaOne instance, int x, int y){
super(x, y);
this.instance = instance;
hitbox = new Rectangle(x, y, 32, 32);
ix = 0;
iy = 1;
}
private void move(){
if(instance.getStage().isCollided(hitbox)){
iy =0;
dead = true;
}
hitbox.x += ix;
hitbox.y += iy;
}
public boolean isDead() {return dead;}
public Rectangle getHitbox() {return hitbox; }
public void draw(Graphics g){
move();
g.setColor(Color.MAGENTA);
g.fillRect(hitbox.x, hitbox.y, hitbox.height, hitbox.width);
}
}
You are using a Rectangle class to represent the position of your box (even though you call it the hitbox), Rectangle does indeed have members x and y which are integers and so when you call
rectangle.x+=0.5f;
What you are really calling is rectangle.x+=(int)0.5f; and (int)0.5f==0.
The Rectangle class is simply inappropriate for holding the position of the box if you want float precision. Consider holding the box's real position as a double or float and casting to int to render it.
So your rendering code would become;
g.fillRect((int)positionX,(int)positionY, hitbox.height, hitbox.width);
where positionX and positionY are doubles. (You could also use Vector2d if you'd prefer to keep x and y together)
Other points
You seem to be extending an Entity class with x,y,w and h and yet never use them, this seems dangerous, why are you extending Entity but recreating your own positional code.
Your game loop isn't shown, however, I can see that you hard code the change in x and y. This is presumably because in your game loop you 'ask for' some frame speed, say 60fps and assume you'll get it. This works fine on a resource rich system, but as soon as you have any resource shortage you will start getting frames that are shorter than 60fps. In most games you don't even notice this because it just makes a larger jump to compensate but here you assume 60fps. It is wise to get an actual frame time and multiply that by a velocity to get you change in x and y.
Related
I'm all new to this and doing a beginner's lecture on Java (with Processing). Our assignment this time is the bouncing ball. I've (sort of) successfully gotten it to move the way it's supposed to and put it into a class, but I can't get the array right.
Here's the version using the class:
class Ball {
float x;
float y;
float ySpeed;
float gravity;
int counter = 0;
Ball()
{
x = 300;
y = 300;
ySpeed = 2.5;
gravity = 0.2;
}
void move()
{
y = y + ySpeed;
ySpeed = ySpeed + gravity;
if (y > height-25 )
{ySpeed = ySpeed * -0.85;
y = height-25;
counter++;
}
println(counter);
if(counter >= 17)
{ySpeed=0;
y=height-25;}
}
void display()
{
ellipse(x,y,50,50);
}
}
//using the class:
Ball b1;
void settings()
{
size(800,600);
}
void setup()
{
b1 = new Ball();
}
void draw()
{
background(0);
b1.move();
b1.display();
}
Here's what I ended up with after messing it up completely.
//class Ball
class Ball {
float[] x;
float[] y;
float[] ySpeed;
float[] gravity;
int i;
int counter = 0;
//constructor
Ball()
{
x[i] = 300;
y[i] = 300;
ySpeed[i] = 2.5;
gravity[i] = 0.2;
}
void move()
{
y[i] = y[i] + ySpeed[i];
ySpeed[i] = ySpeed[i] + gravity[i];
//changes direction; (-25) to avoid movement beyong boundary
if (y[i] > height-25 )
{ySpeed[i] = ySpeed[i] * -0.85;
y[i] = height-25;
}
println(counter);
if(counter >= 17)
{ySpeed[i]=0;
y[i]=height-25;}
}
void display()
{
//draw ellipse
ellipse(x[i],y[i],50,50);
}
}
//using the class
final int i = 9;
Ball[] Balle = new Ball[10];
void settings()
{
size(800,600);
}
void setup()
{
Balle[i] = new Ball();
for (int i = 0; i < Balle.length; i++)
{Balle[i] = new Ball(x[i],y[i],50,50), i*4);
}
}
I suppose this looks weird because it's picked together from several different help pages... the current error is "variable x does not exist" on
{Balle[i] = new Ball(x[i],y[i],50,50), i*4);
I'm aware there are several other problems.
Right now I'm quite lost in figuring out how it works. Could somebody give me a hint?
variable x does not exist - It's because you don't have x as a global variable, but as a class variable, which is therefore only accessible from within the Ball class or by an instance of the Ball class. I don't exactly know why you're using arrays for x and y, primitives would do just fine. And don't forget to add the draw() method, as in processing, that serves as the 'main loop', it gets executed every 0.x sec (frameRate) so you MUST use that as well. Your other functions like display() etc.. can also be called from within the draw function.
Geez, what did I even do there?
Here it is:
Ball[] balls = new Ball[10];
void settings()
{
size(600,800);
}
void setup()
{
for (int i = 0; i < balls.length; i++)
{
balls[i] = new Ball();
}
}
void draw()
{ background(0);
for (int i = 0; i < balls.length; i++)
{
balls[i].move();
balls[i].display();
}
}
Is programming like that, stumbling around in the dark until you get hit by a brick...?
Here's a pseudo code.
If ball <= bottom, reverse the speed of ball.
(That means when it hits the floor, the speed reverses. Multiply it with -1)
Other wise, speedOfBall = speed - (gravity*time);
You can easily calculate the displacement in terms of coordinates as s = velocity*time + .5*gravity*time^2.
package tictactoe;
import processing.core.PApplet;
public class TicTacToe extends PApplet {
int cols = 3;
int rows = 3;
int h;
int w;
public static void main(String[] args) {
PApplet.main("tictactoe.TicTacToe");
}
public void setup() {
//Organization for size of columns and rows
w = width / cols;
h = height / rows;
}
public void settings() {
size(300, 300);
}
public void draw() {
//Draw a tic-tac-toe grid
background(255);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
stroke (0);
noFill();
rect(i*w, j*h, w, h);
}
}
}
public class GridSquare{
//Game state (x's and o's), variables, etc.
public float x;
public float y;
public float w;
public float h;
public int state;
public void drawTurn() {
if (state == 0) {
ellipse(x+w/2,y+h/2,w,h);
}
if (state == 1) {
line(x,y,x+w,y+h);
line(x+w,y,x,y+h);
}
}
//Trouble understanding Grid Detection
void onClick(int clickedX, int clickedY, int turn) {
if (clickedX > x && clickedX < x + w && clickedY > y && clickedY < y + h) {
}
}
}
}
I am having trouble understanding the grid detection if statement. Since the parameters x, y, w, and h all had a semi colon when being defined in the GridSquare class, wouldn't that mean that those variables all equal 0? In that case, wouldn't the if statement be checking if the click x integer is greater than 0, and clicked x is less than 0 (x) + 0 (w)? Or am I wrong, and are the variables representing integers previously defined in the code?
It might be more easily understood if you think about having multiple games (GridSquares) going on at the same time, each with a border around it, and each being drawn on the same panel. The check is simply determining if the click in the panel is valid for that game (GridSquare). With multiple games at once, each one would have a different value for x and y; imagining two games, side by side, the first would probably have (x=0, y=0), but the second game would be at least 300 units (pixels, perhaps) to the right, giving values (x=300, y=0).
I'm making a rudimentary particle simulator in Java. For now, all I've done is make the particles atract each other with an equivalent to the electrical force. This part works fine (or at least as well as you would expect for such a basic model).
However, when I add a few particles, the program loses their values for position, velocity and acceleration, but does not lose other data (like, for example, their ID number). This does not always happens with the same amount of particles. Sometimes it happens when I add the fourth, fifth, second or third particle, but never with the first one. It always happens when I click to add a particle, and after it fails, I can no longer add anything (which is odd), and the particles don't move anymore (as you would expect, being their velocities and accelerations 0).
I am storing the particles in an ArrayList. The array does not lose the data (I've checked, the objects are in there, and I can even call their toString() method and retrieve their ID). The problem seems to be related to synchronization (given that it doesn't always happen at the same moment, it seems to be a bit random), but I can't figure out what it is.
I leave all the relevant code below.
public class Scene implements KeyListener, MouseListener, MouseMotionListener{
public static ArrayList<Particle> particleArray = new ArrayList<Particle>();
public static Object particleLock = new Object();
public void update() {
synchronized(particleLock) {
for(Particle particle: particleArray) {
double resultX = 0;
double resultY = 0;
for(int i = 0; i<particleArray.size(); i++) {
if(i != particleArray.indexOf(particle)) {
double[] result = PhysicsEngine.applyElectircalForce(particle, particleArray.get(i));
resultX += result[0];
resultY += result[1];
}
}
particle.netForceX = resultX;
particle.netForceY = resultY;
particle.update();
}
}
}
public void mousePressed(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
boolean positive = true;
if(e.getButton() == MouseEvent.BUTTON1) {
positive = true;
} else if(e.getButton() == MouseEvent.BUTTON3) {
positive = false;
}
synchronized(particleLock){
particleArray.add(new Particle(mouseX, mouseY, positive));
System.out.println("New particle added at " + mouseX + ", " + mouseY);
}
}
}
public class Particle{
public double x;
public double y;
public Point2D position;
public double velX;
public double velY;
public double acX;
public double acY;
private Color particleColor;
private int radius = 10;
// PHYSICS
public double mass;
public double charge;
public double netForceX;
public double netForceY;
private boolean positive;
public Particle(double x, double y, boolean positive) {
this.x = x - radius;
this.y = y - radius;
this.velX = 3;
this.velY = 2;
this.acX = 0;
this.acY = 0;
this.mass = 100;
this.positive = positive;
if(positive) {
this.charge = defaultCharge;
} else {
this.charge = defaultCharge*(-1);
}
this.position = new Point2D.Double(x, y);
particleColor = Color.WHITE;
}
public void update() {
acX = netForceX / mass;
acY = netForceY / mass;
velX += acX;
velY += acY;
if(x<=0 || x>=Simulation.WIDTH - 23){
velX = velX * -1;
x+= velX;
}
if(y<=0 || y>=Simulation.HEIGHT - 35){
velY = velY * -1;
y+= velY;
}
synchronized(Scene.particleLock) {
for(Particle otherPart: Scene.particleArray) {
if(otherPart.equals(this)) {
continue;
}
double distance = otherPart.position.distance(position);
if(distance <= radius + otherPart.radius) {
//aplicar lo que sé de choques de alguna manera
}
}
}
x+= velX;
y+= velY;
position.setLocation(x, y);
}
}
public class PhysicsEngine {
static double electricalConstant = 100000;
public static double[] applyElectircalForce(Particle thisPart, Particle otherPart) {
double distance = otherPart.position.distance(thisPart.position);
double angle = Math.asin(Math.abs(thisPart.y - otherPart.y)/distance);
double force = (electricalConstant * thisPart.charge * otherPart.charge)/Math.pow(distance, 2);
double forceX = force * Math.cos(angle);
double forceY = force * Math.sin(angle);
if(otherPart.x < thisPart.x) {
forceX = forceX*(-1);
}
if(otherPart.y < thisPart.y) {
forceY = forceY*(-1);
}
double[] result = {forceX, forceY};
return result;
}
}
I once had a similar problem with synchronization when I was working on an android project, try declaring particleArray volatile so that the compiler knows that particleArray will be changed on other or multiple threads. If that does not work I would suggest using a queue to push changes to the particle array from different threads and then pulling the intended changes to the array list in the update method to update your particle array list. In my experience changing values directly between different threads almost always causes problems.
I found some answers in internet which explain how to make a ball bouncing, but some of them don't helped me (because bounces are not random), and some are very difficult (my knowledge in physics are limited).
Problem : I have a ball which move and bounce, but not randomly, and I want to make this ball bouncing randomly.
I already have this piece of code :
Public Class Ball{
/** Coordinates */
private int x, y;
/** Speed of the ball*/
private int speedX, speedY;
public Ball(int x, int y, int speedX, int speedY) {
this.x = x ;
this.y = y ;
this.speedX = speedX;
this.speedY = speedY;
}
public void moveAndBounce() {
x += speedX ;
y += speedY ;
// Assuming that touchWallHorizontal() and touchWallHorizontal() work
if (touchHorizontalWall()) {
speedX = -speedX ;
}
if (touchVerticalWall()) {
speedY = -speedY ;
}
}
public static void main (String [] args){
Ball ball = new Ball(); // Initialisation
while (true){
ball.moveAndBounce() ;
}
}
}
It works perfectly, but the ball movement is always the same (a rectangle).
Question : is there a way to have a random bouncing without add attributes to the ball (just with coordinates and speed) ?
And if not, is there not too difficult solution to resolve this problem ?
Thanks in advance !
Problem solved. Here is the new code for moveAndBounce() method (Thanks to johnHopkins) :
public void moveAndBounce() {
x += speedX ;
y += speedY ;
Random random = new Random();
if (touchHorizontalWall()) {
if (speedX > 0) {
// New speed between 10 and 15 (you can choose other)
setSpeedX(-random.nextInt(15) + 10);
} else {
setSpeedX(random.nextInt(15) + 10
}
}
if (touchVerticalWall()) {
if (speedY > 0) {
setSpeedY(-random.nextInt(15) + 10);
} else {
setSpeedY(random.nextInt(15) + 10);
}
}
}
In the method bounce() the value of count in first increment is not taken forward to second increment..I meant supose count=0..then first time i increment count its value becomes 1 nd second time also the vaue becomes 1..thats may be because both count are stored in different memory location...if i make count static then each time i run the application it retains the value stored in it last time which i don't want..i want the value of count in first increment should be taken forward to second increment...also i can't put count outside if loop inside bounce() method as it will give the wroung output..what should i do?
public class Ball {
private Point p; //Represents the x and y position of the Ball
private int c; //Represents the color of the Ball
private int r; //Represents the Radius of the Ball.
private int dx; //Represents the change in x position of the Ball. (Horizontal Speed)
private int dy; //Represents the change in y position of the Ball. (Vertical Speed)
private Paint paint; //Android Object holding the color for drawing on the canvas
public int count = 0;
public Ball(int x,int y,int col,int radius)
{
p=new Point(x,y);
c=col;
r=radius;
paint=new Paint();
dx=0;
dy=0;
}
public int getCount()
{return count;
}
public int getX() //Returns the x position of the ball as an integer
{return p.x;
}
public int getY() //Returns the y position of the ball as an integer
{
return p.y;
}
public int getRadius() //Returns the Radius of the ball as an integer
{return r;
}
public Paint getPaint() //Returns the Paint of the Ball as a Paint Object
{return paint;
}
public void setColor(int col) //Sets the Color of the Ball
{c=col;
if (paint == null)
paint = new Paint();
paint.setColor(col);
}
public void goTo(int x,int y) //Sets the x and y positions of the Ball
{p.x=x;
p.y=y;
}
public void setDX(int speed) //Sets the Horizontal Speed of the Ball
{dx=speed;
}
public void setDY(int speed) //Sets the Vertical Speed of the Ball
{
dy=speed;
}
public void move() //Changes the x and y position by the dx and dy values
{
p.x=p.x+dx;
p.y=p.y+dy;
}
public void setX(int x)
{
p.x = x;
}
public void setY(int y)
{
p.y = y;
}
public int getDX()
{
return p.x;
}
public int getDY()
{
return p.y;
}
public void bounce(Canvas canvas) //Bounces off the Sides of the Canvas
{
move();
if(p.x>canvas.getWidth()|| p.x<0)
{
count++;
dx=dx * -1;
}
if(p.y>canvas.getWidth()|| p.y<0)
{
count++;
dy=dy * -1;
}
MainActivity.tv.setText(String.valueOf(getCount()));
}
}
Just thought I should add my comments as an answer. You should only create one instance of the Ball class and use it. Each time you create a new instance of Ball, you set count = 0
You should use singleton class to maintain your count increment ,and whenever application starts make it zero . instead of static making Singleton class and maintain count in that class using setter and getter method is beat easy .