Revelations
One small step for others, one giant leap for ME!
6In my previous blog post, I was talking about how I failed to extend the Rectangle class, and had to step back and learn a few more basics. Now approximately 8 hours later, a lot of pages, videos and other things (completely unrelated to Java), I’ve managed to get it working.
For me this a huge step in the right direction, and when the penny finally hit, it didn’t take more than a few minutes to actually change the code to reflect what I wanted to do.
Again, the original spawnRaindrop() code:
1 2 3 4 5 6 7 8 9 | private void spawnRaindrop() { Rectangle raindrop = new Rectangle(); raindrop.x = MathUtils.random(0, 800-48); raindrop.y = 480; raindrop.width = 48; raindrop.height = 48; raindrops.add(raindrop) lastDropTime = TimeUtils.nanoTime(); } |
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800-48);
raindrop.y = 480;
raindrop.width = 48;
raindrop.height = 48;
raindrops.add(raindrop)
lastDropTime = TimeUtils.nanoTime();
}
And the modified version
1 2 3 4 5 6 7 8 9 10 | private void spawnRaindrop() { Raindrop raindrop = new Raindrop(); raindrop.x = MathUtils.random(0, 800-48); raindrop.y = 480; raindrop.width = 48; raindrop.height = 48; raindrop.speed = MathUtils.random(50,200); raindrops.add(raindrop); lastDropTime = TimeUtils.nanoTime(); } |
private void spawnRaindrop() {
Raindrop raindrop = new Raindrop();
raindrop.x = MathUtils.random(0, 800-48);
raindrop.y = 480;
raindrop.width = 48;
raindrop.height = 48;
raindrop.speed = MathUtils.random(50,200);
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
The Raindrop class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.badlogic.drop; import com.badlogic.gdx.math.Rectangle; public class Raindrop extends Rectangle { float speed; public Raindrop() { super(); } public Raindrop(float x, float y, float width, float height, float speed) { super(x, y, width, height); this.speed = speed; } } |
package com.badlogic.drop;
import com.badlogic.gdx.math.Rectangle;
public class Raindrop extends Rectangle {
float speed;
public Raindrop() {
super();
}
public Raindrop(float x, float y, float width, float height, float speed) {
super(x, y, width, height);
this.speed = speed;
}
}
And the entire Drop.java code with the new shiny Raindrop class in action (I took the liberty of copying directly from the tutorial page since I had mangled the original code somewhat awful)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | package com.badlogic.drop; import java.util.Iterator; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.TimeUtils; public class Drop implements ApplicationListener { Texture dropImage; Texture bucketImage; Sound dropSound; Music rainMusic; SpriteBatch batch; OrthographicCamera camera; Rectangle bucket; Array<Raindrop> raindrops; long lastDropTime; @Override public void create() { // load the images for the droplet and the bucket, 48x48 pixels each dropImage = new Texture(Gdx.files.internal("droplet.png")); bucketImage = new Texture(Gdx.files.internal("bucket.png")); // load the drop sound effect and the rain background "music" dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav")); rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3")); // start the playback of the background music immediately rainMusic.setLooping(true); rainMusic.play(); // create the camera and the SpriteBatch camera = new OrthographicCamera(); camera.setToOrtho(false, 800, 480); batch = new SpriteBatch(); // create a Rectangle to logically represent the bucket bucket = new Rectangle(); bucket.x = 800 / 2 - 48 / 2; // center the bucket horizontally bucket.y = 20; // bottom left corner of the bucket is 20 pixels above the bottom screen edge bucket.width = 48; bucket.height = 48; // create the raindrops array and spawn the first raindrop raindrops = new Array<Raindrop>(); spawnRaindrop(); } private void spawnRaindrop() { Raindrop raindrop = new Raindrop(); raindrop.x = MathUtils.random(0, 800-48); raindrop.y = 480; raindrop.width = 48; raindrop.height = 48; raindrop.speed = MathUtils.random(0,50); raindrops.add(raindrop); lastDropTime = TimeUtils.nanoTime(); } @Override public void render() { // clear the screen with a dark blue color. The // arguments to glClearColor are the red, green // blue and alpha component in the range [0,1] // of the color to be used to clear the screen. Gdx.gl.glClearColor(0, 0, 0.2f, 1); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // tell the camera to update its matrices. camera.update(); // tell the SpriteBatch to render in the // coordinate system specified by the camera. batch.setProjectionMatrix(camera.combined); // begin a new batch and draw the bucket and // all drops batch.begin(); batch.draw(bucketImage, bucket.x, bucket.y); for(Rectangle raindrop: raindrops) { batch.draw(dropImage, raindrop.x, raindrop.y); } batch.end(); // process user input if(Gdx.input.isTouched()) { Vector3 touchPos = new Vector3(); touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0); camera.unproject(touchPos); bucket.x = touchPos.x - 48 / 2; } if(Gdx.input.isKeyPressed(Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime(); if(Gdx.input.isKeyPressed(Keys.RIGHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime(); // make sure the bucket stays within the screen bounds if(bucket.x < 0) bucket.x = 0; if(bucket.x > 800 - 48) bucket.x = 800 - 48; // check if we need to create a new raindrop if(TimeUtils.nanoTime() - lastDropTime > 1000000000) spawnRaindrop(); // move the raindrops, remove any that are beneath the bottom edge of // the screen or that hit the bucket. In the later case we play back // a sound effect as well. Iterator<Raindrop> iter = raindrops.iterator(); while(iter.hasNext()) { Raindrop raindrop = iter.next(); raindrop.y -= raindrop.speed * Gdx.graphics.getDeltaTime(); if(raindrop.y + 48 < 0) iter.remove(); if(raindrop.overlaps(bucket)) { dropSound.play(); iter.remove(); } } } @Override public void dispose() { // dispose of all the native resources dropImage.dispose(); bucketImage.dispose(); dropSound.dispose(); rainMusic.dispose(); batch.dispose(); } @Override public void resize(int width, int height) { } @Override public void pause() { } @Override public void resume() { } } |
package com.badlogic.drop;
import java.util.Iterator;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
public class Drop implements ApplicationListener {
Texture dropImage;
Texture bucketImage;
Sound dropSound;
Music rainMusic;
SpriteBatch batch;
OrthographicCamera camera;
Rectangle bucket;
Array<Raindrop> raindrops;
long lastDropTime;
@Override
public void create() {
// load the images for the droplet and the bucket, 48x48 pixels each
dropImage = new Texture(Gdx.files.internal("droplet.png"));
bucketImage = new Texture(Gdx.files.internal("bucket.png"));
// load the drop sound effect and the rain background "music"
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// start the playback of the background music immediately
rainMusic.setLooping(true);
rainMusic.play();
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
// create a Rectangle to logically represent the bucket
bucket = new Rectangle();
bucket.x = 800 / 2 - 48 / 2; // center the bucket horizontally
bucket.y = 20; // bottom left corner of the bucket is 20 pixels above the bottom screen edge
bucket.width = 48;
bucket.height = 48;
// create the raindrops array and spawn the first raindrop
raindrops = new Array<Raindrop>();
spawnRaindrop();
}
private void spawnRaindrop() {
Raindrop raindrop = new Raindrop();
raindrop.x = MathUtils.random(0, 800-48);
raindrop.y = 480;
raindrop.width = 48;
raindrop.height = 48;
raindrop.speed = MathUtils.random(0,50);
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
@Override
public void render() {
// clear the screen with a dark blue color. The
// arguments to glClearColor are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the bucket and
// all drops
batch.begin();
batch.draw(bucketImage, bucket.x, bucket.y);
for(Rectangle raindrop: raindrops) {
batch.draw(dropImage, raindrop.x, raindrop.y);
}
batch.end();
// process user input
if(Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
bucket.x = touchPos.x - 48 / 2;
}
if(Gdx.input.isKeyPressed(Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Keys.RIGHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime();
// make sure the bucket stays within the screen bounds
if(bucket.x < 0) bucket.x = 0;
if(bucket.x > 800 - 48) bucket.x = 800 - 48;
// check if we need to create a new raindrop
if(TimeUtils.nanoTime() - lastDropTime > 1000000000) spawnRaindrop();
// move the raindrops, remove any that are beneath the bottom edge of
// the screen or that hit the bucket. In the later case we play back
// a sound effect as well.
Iterator<Raindrop> iter = raindrops.iterator();
while(iter.hasNext()) {
Raindrop raindrop = iter.next();
raindrop.y -= raindrop.speed * Gdx.graphics.getDeltaTime();
if(raindrop.y + 48 < 0) iter.remove();
if(raindrop.overlaps(bucket)) {
dropSound.play();
iter.remove();
}
}
}
@Override
public void dispose() {
// dispose of all the native resources
dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
rainMusic.dispose();
batch.dispose();
}
@Override
public void resize(int width, int height) {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
}I hope this is helpful to someone else, if not at least I have some place to find this when I wake up and have forgotten all about it.
Drop 1
Me 1
Your move Java!
On another note, I really need to add a couple of things to this wordpress blog. Color coded syntax and an easier way to add the code would be a start. Also I’ve been asked to add some syndication for the entire site, so I’ll look into that sometime soon as well.
Wait.. back up a bit, I’m missing something
0After spending a little time with Eclipse and going deeper into libGDX, and going through one of the libGDX tutorials, namely this oneĀ https://code.google.com/p/libgdx/wiki/SimpleApp#Project_Setup. I decided to try and expand a bit on it.
“Drop” which is the name of the game you create in that short tutorial, taught me a few things, but I realized that I would have to stop and go back a bit when I wanted to extend on the Rectangle class in libGDX. Let me try and explain my reasons for wanting to extend that class.
If you follow the code precisely you end up with a small game, where you move a bucket in the bottom of the screen around, to catch drops falling at random spots from the top of the screen (Zen indeed). Now all these drops that are falling, fall with the same speed, so I wanted to randomize the speed of the drops, to add a little variation to the game, merely for learning purposes.
This is the section of the code that spawns the raindrops
1 2 3 4 5 6 7 8 9 | private void spawnRaindrop() { Rectangle raindrop = new Rectangle(); raindrop.x = MathUtils.random(0, 800-48); raindrop.y = 480; raindrop.width = 48; raindrop.height = 48; raindrops.add(raindrop); lastDropTime = TimeUtils.nanoTime(); } |
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800-48);
raindrop.y = 480;
raindrop.width = 48;
raindrop.height = 48;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
Now I wanted to add a little more to it
1 | raindrop.speed = MathUtils.random(50, 200); |
raindrop.speed = MathUtils.random(50, 200);
However to do this I needed to extend the Rectangle class, which with my knowledge of Java was not possible.
So the only way for me to go for now, is to read up a bit more about the basics of Java, and take it slower. For this I’ve allied myself with a book called “Head First Java”, which so far seems like a very good read. Also, Mario’s Beginning Android Games, but that will probably be used on a later time, since I first need to take a few steps back.
It looks like the score for now is.
Drop 1
Me 0
But the battle is not over yet!