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.
Related
I am trying to create some trippy "animation" such as this image; Trippy circles
I can just place another circle into the circle by brute-forcing it. However, I am pretty sure that there is an easier way of doing it by either using "while" or "for". I am pretty new to coding so I have no idea which logic to use.
Here is my brute-forced code below.
int m = millis();
void setup(){
size(1136,936);
}
void draw(){
ellipseMode(CENTER);
frameRate(1.3);
background(255);
if (millis() > m + 1000){
for (int diameter = 0; diameter < 500; diameter = diameter+1) {
float r1 = random(1,1000);
float r2 = random(1,900);
fill(255);
circle(r1, r2, diameter);
fill(0);
circle(r1,r2,diameter/2);
}
}
}
Thanks!
This comes close to what your example looks like (based on your original code):
int m = millis();
void setup(){
size(1136,936);
}
int colors[] = { 0, 255 };
void draw(){
ellipseMode(CENTER);
//frameRate(1.3);
background(255);
if (millis() > m + 1000) {
for (int i = 0; i < 500; i = i+1) {
float x = random(1,1000);
float y = random(1,900);
float radius = 300;
float delta = 30;
int counter = 0;
while (radius >= delta) {
fill(colors[counter % colors.length]);
ellipse(x, y, radius, radius);
counter++;
radius -= delta;
}
}
}
}
I am trying to make Space Invaders in Processing. I am currently working on getting the enemy to move correctly. I have got them to be drawn in the right spot but I haven't gotten them to be moved correctly. Here is my code:
PImage mainPlayer;
PImage enemyPlayer;
float Xspeed = 60;
float Yspeed = 60;
float X;
float Y;
Enemy EnemyPlayer = new Enemy("EnemyPlayerSpaceInvaders.png", 10, 10, 6);
void setup() {
size(1400, 800);
//enemyPlayer = loadImage("EnemyPlayerSpaceInvaders.png");
mainPlayer = loadImage("MainPlayerSpaceInvaders.png");
}
void draw() {
background(0);
Enemy[] enemyPlayer = new Enemy[60];
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
enemyPlayer[j *i] = new Enemy("EnemyPlayerSpaceInvaders.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
if(enemyPlayer[j * i].alive){
enemyPlayer[j * i].Draw();
}
enemyPlayer[j *i].moveAndDraw(6);
}
}
}
class Enemy {
boolean alive = true;
float x;
float y;
float speed;
String playerTexFile;
PImage playerTex;
Enemy(String PlayerTexFile, float X, float Y, float Speed){
x = X;
y = Y;
speed = Speed;
playerTexFile = PlayerTexFile;
}
void Draw(){
playerTex = loadImage(playerTexFile);
image(playerTex, x, y);
}
void moveAndDraw(float Speed){
playerTex = loadImage(playerTexFile);
if(alive){
x += Speed;
if (x >= 1300) {
x = 100;
y += 50;
}
}
}
}
Here is my result:
The Draw function works but what you're seeing that is messing it up is the moveAndDraw() function.
And the enemy drawings aren't moving. I have made this before with c++ SFML but in that there is a very basic getPosition function. The reason I want to get position is that right now I'm having to use inaccurate numbers as the X and Y position and for the enemy to move correctly I need to know exactly what it's position is. I have checked multiple pages on processing.org but none of them helped. I haven't found any getPosition void and all the ones I've seen other people using a void to do this I just haven't been able to get it to work. If there is some code that could get me this to work or just some function I've looked over and even a website page I could look at I'd be open to it. Please tell me anything I can do to get this working.
The issue is that you recreate the enemies in every frame at it's initial position:
void draw() {
background(0);
Enemy[] enemyPlayer = new Enemy[60];
for (int i = 0; i < 5; i += 1) {
for (int j = 0; j < 11; j += 1) {
enemyPlayer[j *i] = new Enemy("EnemyPlayerSpaceInvaders.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
// [...]
}
You've to:
Create a global array of enemies Enemy[] enemyPlayer (and delete PImage enemyPlayer).
Create and initialize the enemies in setup.
Use and move the existing enemies in draw:
Further note, that your loops doesn't do what you expect it to do. Create the enemies in 2 nested loops. If i runs from o to 6 and j from 0 to 10, the the index of an enemy is i*10 + j.
The enemies can be moved in a single loop from 0 to enemyPlayer.length.
//PImage enemyPlayer; <--- DELETE
// global array of enemies
Enemy[] enemyPlayer = new Enemy[60];
// [...]
void setup() {
size(1400, 800);
mainPlayer = loadImage("MainPlayerSpaceInvaders.png");
// create enemies
for (int i = 0; i < 6; i += 1) {
for (int j = 0; j < 10; j += 1) {
enemyPlayer[i*10 + j] = new Enemy("rocket64.png", 50 + j * 100, 5 + 75 * i, 6);
}
}
}
void draw() {
background(0);
// move enemies
for(int i = 0; i < enemyPlayer.length; ++i ) {
if(enemyPlayer[i].alive){
enemyPlayer[i].Draw();
}
enemyPlayer[i].moveAndDraw(6);
}
}
this code is supposed to have an ellipse with a "trail" of ellipses behind it that decrease in size and become more white. It is called "Smoke Trail" and the ellipses in this code work properly for the most part. There is one problem in the code where one of the ellipses draws over the trail and doesn't go behind like all the others. I think it has something to do with the first or last ellipse of the for loop
int count = 75;
int made = 0;
Smokes[] arrSmokes = new Smokes[count];
void setup()
{
size(800, 800);
}
void draw()
{
background(255);
if(made < count)
{
arrSmokes[made] = new Smokes();
made += 1;
}
for(int i = 0; i < made; i += 1)
{
arrSmokes[i].render();
}
}
public class Smokes{
int xCoord, yCoord;
float size;
Smokes()
{
xCoord = mouseX;
yCoord = mouseY;
size = 100;
}
void render()
{
noStroke();
ellipse(xCoord, yCoord, size, size);
size -= 4;
if(size <= 0)
{
xCoord = mouseX;
yCoord = mouseY;
size = 100;
}
}
}
Since you are keeping your old Instances of smoke and just reset them you have to store the top of your circles. Just use a Integer for that.
int top = 0;
Now you have to give every circle its number in the array...
if (made < count) {
arrSmokes[made] = new Smokes(made);
made ++;
}
/*
...
*/
int number;
Smokes(int number)
{
this.number = number;
//Initialyze
}
Now you have to change the top of your list every time you reset the Smoke particle.
void reset()
{
xCoord = mouseX;
yCoord = mouseY;
c = 0;
size = 100;
top = number;
}
Your for-loop should now start at the entry one above the top and go the way up to the end of the array and then jump to the first entry and run until it reaches the top entry.
for (int i = (top+1)%count; i != top; i = (i+1)%count) {
if (i >= made) continue;
arrSmokes[i].render();
}
Since you are not allowed to change the top while executing "render();" you have to add a function "evaluate();" which you run after having done every "render();".
void evaluate()
{
c += 10.2;
size -= 4;
if (size <= 0) {
reset();
}
}
void render()
{
noStroke();
fill(c);
ellipse(xCoord, yCoord, size, size);
}
Now you should be good to go. Here is the whole source again if I messed you up a bit: https://pastebin.com/urzbzmEb
But I recommend to use a ArrayList instead since Java is object-based and has its own garbage-collector. The good thing at the ArrayList is you know at every time that the last object in the list is the top circle.
Here is how it would look like with an ArrayList.
ArrayList<Smokes> smokes = new ArrayList<Smokes>();
void setup() {
size(800, 800);
}
void draw() {
background(255);
smokes.add(new Smokes(mouseX, mouseY));
for (int i = 0; i < smokes.size(); i ++) {
smokes.get(i).render();
}
}
public class Smokes {
int xCoord, yCoord;
float size = 100, c = 0;
Smokes(int x, int y) {
xCoord = x;
yCoord = y;
}
void render() {
noStroke();
fill(c);
ellipse(xCoord, yCoord, size, size);
c += 10.2;
size -= 4;
if (size <= 0) {
smokes.remove(this);
}
}
}
I'm trying to learn how to make a 2D Game without Game Engines, anyways I already created a background scrolling right now my goal is to make my character jump. But the thing is whenever I start my app the character is spinning up and down and it will just go away to the background.
Here's my character code
public class Deer extends GameCharacter {
private Bitmap spritesheet;
private double dya;
private boolean playing;
private long startTime;
private boolean Jump;
private Animate Animation = new Animate();
public Deer(Bitmap res, int w, int h, int numFrames) {
x = 20;
y = 400;
dy = 0;
height = h;
width = w;
Bitmap[] image = new Bitmap[numFrames];
spritesheet = res;
for (int i = 0; i < image.length; i++)
{
image[i] = Bitmap.createBitmap(spritesheet, i*width, 0, width, height);
}
Animation.setFrames(image);
Animation.setDelay(10);
startTime = System.nanoTime();
}
public void setJump(boolean b){
Jump = b;
}
public void update()
{
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100)
{
}
Animation.update();
if(Jump){
dy = (int)(dya+=5.5);
}
else{
dy = (int)(dya+=5.5);
}
if(dy>14)dy = 14;
if(dy>14)dy = -14;
y += dy*2;
dy = 0;
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(Animation.getImage(),x,y,null);
}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
public void resetDYA(){dya = 0;}
}
x - character's horizontal position
y - character's vertical position
dx - character's horizontal acceleration
dy - character's vertical acceleration
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
if(!deer.getPlaying()) {
deer.setPlaying(true);
}
deer.setJump(true);
return true;
}
return super.onTouchEvent(event);
}
I can't say for sure if this is the only problem because you have other suspicious code but it looks like you jump no matter what.
if(Jump){
dy = (int)(dya+=5.5);
} else {
dy = (int)(dya+=5.5);
}
If Jump is true you set the vertical acceleration. But you also set the vertical acceleration to the same value if Jump is false. You also don't show in your code where Jump is ever set to false.
Another odd bit of code is:
if(dy>14)dy = 14;
if(dy>14)dy = -14;
Here, if dy>14 you set it to 14. Then you check dy>14 immediately after. Of course, this time it's false. But because those two conditions are the same the second one will never pass since the one before it ensures it won't. The only other option is they both fail. IOW, you'll never be able to enter the second if.
All that aside, I'm not sure why you're taking this approach. You can simply rely on physics equations with constant acceleration, give an initial velocity, check for a collision with the ground (or at least the original height), and just let it run. For example:
// These are the variables you need.
int x = 200, y0 = 0, y = 0, velocity = 15;
double t = 0.0, gravity = -9.8;
// This is the statement that should run when you update the GUI.
// It is the fundamental equation for motion with constant acceleration.
// The acceleration is the gravitational constant.
y = (int) (y0 + velocity * t + .5 * gravity * t * t);
if (y < 0) {
y = y0 = 0;
//Stop jumping!
Jump = false;
} else {
// Swap the y values.
y0 = y;
// Increase the time with the frame rate.
t += frameRate;
}
// Draw the character using the y value
The best part about this is you don't need to worry about when you get to the maximum height because the equation will automatically bring you down. It also looks more natural as if the mechanics are real. Try it out.
A simple Swing example that you can play around with. Note that the values are different to deal with the way the components are drawn to the screen. Normally, you would deal with that with transformations but this will do for the task.
public class Main {
static Timer timer;
Main() {
JFrame frame = new JFrame("Hello sample");
frame.setSize(new Dimension(550, 550));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
timer = new Timer(5, (e) -> panel.repaint());
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::new);
}
class MyPanel extends JPanel {
int x = 200, y0 = 300, y = 0, w = 200, h = 200, v = -8;
double t = 0.0, gravity = 9.8;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
y = (int) (y0 + v * t + .5 * gravity * t * t);
if (y > 300) {
y = y0 = 300;
// To prevent it from stopping comment the timer.stop() and
// uncomment the t = 0.0 statements.
//t = 0.0;
timer.stop();
} else {
y0 = y;
t += .025;
}
g.drawOval(x, y, w, h);
}
}
}
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.