im working on a little rpg game and today i tried to add shadows.
I saw this tutorial here which is good :)
Pixel Perfect Shader
So following problem :
Test example from the tutorial site, works fine. Theres one cam and the shadows are on the right place.
As soon i use Orthographic cameras from my player sprite, the shadow isnt there where it should be and when im moving the shadow moves with me, he is on the same spot on the display screen but in the world the shadow is moving _/ that looks so :
The SpriteSheet should cast shadows ... but they are on the wrong place :/
Here i didnt moved :
It is very dark, because of the day/night cycle ...
And here i moved a little bit to left :
I dont know why it wont work ... im giving the Orthographic camera out of my main class to the shadow class. Or did i miss something ? :/
My code should be fine, but if anyone wanna see it here is some code :
public class LightSystemShader {
private int lightSize = 500;
private float upScale = 1f; //for example; try lightSize=128, upScale=1.5f
SpriteBatch batch;
OrthographicCamera cam;
BitmapFont font;
FPSLogger fps;
TextureRegion shadowMap1D; //1 dimensional shadow map
TextureRegion occluders; //occluder map
FrameBuffer shadowMapFBO;
FrameBuffer occludersFBO;
Texture casterSprites;
Texture enmyAnimation;
Texture light;
ShaderProgram shadowMapShader, shadowRenderShader;
Array<Light> lights = new Array<Light>();
boolean additive = true;
boolean softShadows = true;
float xKoord = 600;
public static ShaderProgram createShader(String vert, String frag) {
ShaderProgram prog = new ShaderProgram(vert, frag);
if (!prog.isCompiled())
throw new GdxRuntimeException("could not compile shader: " + prog.getLog());
if (prog.getLog().length() != 0)
Gdx.app.log("GpuShadows", prog.getLog());
return prog;
}
public LightSystemShader() {
batch = new SpriteBatch();
ShaderProgram.pedantic = false;
//read vertex pass-through shader
final String VERT_SRC = Gdx.files.internal("data/pass.vert").readString();
// renders occluders to 1D shadow map
shadowMapShader = createShader(VERT_SRC, Gdx.files.internal("data/shadowMap.frag").readString());
// samples 1D shadow map to create the blurred soft shadow
shadowRenderShader = createShader(VERT_SRC, Gdx.files.internal("data/shadowRender.frag").readString());
//the occluders
casterSprites = new Texture("data/cat4.png");
//
enmyAnimation = new Texture("EnemyAnimations/BugIdleStand.png");
//the light sprite
light = new Texture("data/light.png");
cam = new OrthographicCamera(0,0);
cam.setToOrtho(false);
updateMaps();
font = new BitmapFont();
Gdx.input.setInputProcessor(new InputAdapter() {
public boolean touchDown(int x, int y, int pointer, int button) {
float mx = x;
float my = Gdx.graphics.getHeight() - y;
lights.add(new Light(mx, my, randomColor()));
return true;
}
public boolean keyDown(int key) {
if (key==Keys.SPACE){
clearLights();
return true;
} else if (key==Keys.A){
additive = !additive;
return true;
} else if (key==Keys.S){
softShadows = !softShadows;
return true;
}
return false;
}
});
clearLights();
}
public void renderLightSystemShader(OrthographicCamera screenCam){
screenCam = new OrthographicCamera(0,0);
screenCam.setToOrtho(false);
Gdx.gl.glClearColor(0,0,0,0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float mx = Gdx.input.getX();
float my = Gdx.graphics.getHeight() - Gdx.input.getY();
if (additive)
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
for (int i=0; i<lights.size; i++) {
Light o = lights.get(i);
if (i==lights.size-1) {
o.x = mx;
o.y = my;
}
renderLight(o, screenCam);
}
if (additive)
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
//STEP 4. render sprites in full colour
batch.setProjectionMatrix(screenCam.combined);
batch.begin();
batch.setShader(null); //default shader
drawShaderBatch(batch);
//DEBUG RENDERING -- show occluder map and 1D shadow map
/*batch.setColor(Color.BLACK);
batch.draw(occluders, Gdx.graphics.getWidth()-lightSize, 0);
batch.setColor(Color.WHITE);
batch.draw(shadowMap1D, Gdx.graphics.getWidth()-lightSize, lightSize+5);
//DEBUG RENDERING -- show light
batch.draw(light, mx-light.getWidth()/2f, my-light.getHeight()/2f); //mouse
batch.draw(light, Gdx.graphics.getWidth()-lightSize/2f-light.getWidth()/2f, lightSize/2f-light.getHeight()/2f);
*/
//draw FPS
batch.end();
System.out.println(Gdx.graphics.getFramesPerSecond());
}
// draw Lights
void renderLight(Light o, OrthographicCamera screenCam) {
float mx = o.x;
float my = o.y;
screenCam = new OrthographicCamera(0,0);
screenCam.setToOrtho(false);
//STEP 1. render light region to occluder FBO
//bind the occluder FBO
occludersFBO.begin();
//clear the FBO
Gdx.gl.glClearColor(0f,0f,0f,0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//set the orthographic camera to the size of our FBO
screenCam.setToOrtho(false, occludersFBO.getWidth(), occludersFBO.getHeight());
//translate camera so that light is in the center
screenCam.translate(mx - lightSize/2f, my - lightSize/2f);
//update camera matrices
screenCam.update();
//set up our batch for the occluder pass
batch.setProjectionMatrix(screenCam.combined);
batch.setShader(null); //use default shader
batch.begin();
// ... draw any sprites that will cast shadows here ... //
batch.draw(casterSprites, 0, 0);
batch.draw(enmyAnimation,xKoord,600,300,100);
//end the batch before unbinding the FBO
batch.end();
//unbind the FBO
occludersFBO.end();
//STEP 2. build a 1D shadow map from occlude FBO
//bind shadow map
shadowMapFBO.begin();
//clear it
Gdx.gl.glClearColor(0f,0f,0f,0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//set our shadow map shader
batch.setShader(shadowMapShader);
batch.begin();
shadowMapShader.setUniformf("resolution", lightSize, lightSize);
shadowMapShader.setUniformf("upScale", upScale);
//reset our projection matrix to the FBO size
screenCam.setToOrtho(false, shadowMapFBO.getWidth(), shadowMapFBO.getHeight());
batch.setProjectionMatrix(screenCam.combined);
//draw the occluders texture to our 1D shadow map FBO
batch.draw(occluders.getTexture(), 0, 0, lightSize, shadowMapFBO.getHeight());
//flush batch
batch.end();
//unbind shadow map FBO
shadowMapFBO.end();
//STEP 3. render the blurred shadows
//reset projection matrix to screen
screenCam.setToOrtho(false);
batch.setProjectionMatrix(screenCam.combined);
//set the shader which actually draws the light/shadow
batch.setShader(shadowRenderShader);
batch.begin();
shadowRenderShader.setUniformf("resolution", lightSize, lightSize);
shadowRenderShader.setUniformf("softShadows", softShadows ? 1f : 0f);
//set color to light
batch.setColor(o.color);
float finalSize = lightSize * upScale;
//draw centered on light position
batch.draw(shadowMap1D.getTexture(), mx-finalSize/2f, my-finalSize/2f, finalSize, finalSize);
//flush the batch before swapping shaders
batch.end();
//reset color
batch.setColor(Color.WHITE);
//xKoord+=1;
}
void clearLights() {
lights.clear();
lights.add(new Light(Gdx.input.getX(), Gdx.graphics.getHeight()-Gdx.input.getY(), Color.WHITE));
}
static Color randomColor() {
float intensity = (float)Math.random() * 0.5f + 0.5f;
return new Color((float)Math.random(), (float)Math.random(), (float)Math.random(), intensity);
}
void drawShaderBatch(SpriteBatch batch){
batch.draw(casterSprites, 0, 0);
batch.draw(enmyAnimation,600,600,300,100);
}
void updateMaps(){
occludersFBO = new FrameBuffer(Format.RGBA8888, lightSize, lightSize, false);
occluders = new TextureRegion(occludersFBO.getColorBufferTexture());
occluders.flip(false, true);
//our 1D shadow map, lightSize x 1 pixels, no depth
shadowMapFBO = new FrameBuffer(Format.RGBA8888, lightSize, 1, false);
Texture shadowMapTex = shadowMapFBO.getColorBufferTexture();
//use linear filtering and repeat wrap mode when sampling
shadowMapTex.setFilter(TextureFilter.Linear, TextureFilter.Linear);
shadowMapTex.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
//for debugging only; in order to render the 1D shadow map FBO to screen
shadowMap1D = new TextureRegion(shadowMapTex);
shadowMap1D.flip(false, true);
}
public void doDispose(){
batch.dispose();
font.dispose();
shadowMapFBO.dispose();
shadowMapShader.dispose();
shadowRenderShader.dispose();
casterSprites.dispose();
enmyAnimation.dispose();
light.dispose();
occludersFBO.dispose();
}
}
Found it out myself ^^ i forgot to add this to void renderLights :
cam.position.set(positionX,positionY, 0);
Related
I am creating a top-down shooter game, and whenever I move the camera, or zoom, black likes appear like a grid
I am using Tiled to create the map, and I have the camera following my centered box2d body. I have found that making the camera position equal the position of the box2d body with an int cast results in the black lines disappearing like this:
The problem though, is that because I have the game scaled down, the player will move for a second or two and then when the player reaches the next whole number on either axis, the camera snaps to the player, which is not what I want for the game as it's jarring. The player's movement is granular, but, while rounded, the camera's is not. I do not know if this is a problem with my tile sheet or if it's something I can fix by altering some code. I have tried all different kinds of combinations of padding, and values of spacing and margins. So ultimately, how can I have the camera match the player's position smoothly and not cause the black lines? I'd greatly appreciate any help or recommendations. Thank you in advance!
Where I am type casting the player's float position to an int in game class:
public void cameraUpdate(float delta) {
//timeStep = 60 times a second, velocity iterations = 6, position iterations = 2
world.step(1/60f, 6, 2); //tells game how many times per second for Box2d to make its calculations
cam.position.x = (int)playerOne.b2body.getPosition().x;
cam.position.y = (int)playerOne.b2body.getPosition().y;
cam.update();
}
Majority of player class:
public class PlayerOne extends Sprite implements Disposable{
public World world; // world player will live in
public Body b2body; //creates body for player
private BodyDef bdef = new BodyDef();
private float speed = 1f;
private boolean running;
TextureAtlas textureAtlas;
Sprite sprite;
TextureRegion textureRegion;
private Sound runningSound;
public PlayerOne(World world) {
this.world = world;
definePlayer();
textureAtlas = new TextureAtlas(Gdx.files.internal("sprites/TDPlayer.atlas"));
textureRegion = textureAtlas.findRegion("TDPlayer");
sprite =new Sprite(new Texture("sprites/TDPlayer.png"));
sprite.setOrigin((sprite.getWidth() / 2) / DunGun.PPM, (float) ((sprite.getHeight() / 2) / DunGun.PPM - .08));
runningSound = Gdx.audio.newSound(Gdx.files.internal("sound effects/running.mp3"));
}
public void definePlayer() {
//define player body
bdef.position.set(750 / DunGun.PPM, 400 / DunGun.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
//create body in the world
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(12 / DunGun.PPM);
fdef.shape = shape;
b2body.createFixture(fdef);
}
public void renderSprite(SpriteBatch batch) {
float posX = b2body.getPosition().x;
float posY = b2body.getPosition().y;
float posX2 = (float) (posX - .14);
float posY2 = (float) (posY - .1);
sprite.setSize(32 / DunGun.PPM, 32 / DunGun.PPM);
sprite.setPosition(posX2, posY2);
float mouseX = Level1.mouse_position.x; //grabs cam.unproject x vector value
float mouseY = Level1.mouse_position.y; //grabs cam.unproject y vector value
float angle = MathUtils.atan2(mouseY - getY(), mouseX - getX()) * MathUtils.radDeg; //find the distance between mouse and player
angle = angle - 90; //makes it a full 360 degrees
if (angle < 0) {
angle += 360 ;
}
float angle2 = MathUtils.atan2(mouseY - getY(), mouseX - getX()); //get distance between mouse and player in radians
b2body.setTransform(b2body.getPosition().x, b2body.getPosition().y, angle2); //sets the position of the body to the position of the body and implements rotation
sprite.setRotation(angle); //rotates sprite
sprite.draw(batch); //draws sprite
}
public void handleInput(float delta) {
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2 + (5 / DunGun.PPM));
this.b2body.setLinearVelocity(0, 0);
if(Gdx.input.isKeyPressed(Input.Keys.W)){
this.b2body.setLinearVelocity(0f, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.S)){
this.b2body.setLinearVelocity(0f, -speed);
}if(Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, speed);
}
if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, -speed );
}if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, -speed);
}
Where I declare the pixels per meter scale:
public class DunGun extends Game{
public SpriteBatch batch;
//Virtual Screen size and Box2D Scale(Pixels Per Meter)
public static final int V_WIDTH = 1500;
public static final int V_HEIGHT = 800;
public static final float PPM = 100; //Pixels Per Meter
Game render and resize methods:
#Override
public void render(float delta) {
cameraUpdate(delta);
playerOne.handleInput(delta);
//clears screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
cam.zoom -= .01;
}
if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
cam.zoom += .01;
}
mapRenderer.render();
b2dr.render(world, cam.combined); //renders the Box2d world
mapRenderer.setView(cam);
//render our game map
//mapRenderer.render(); // renders map
//mapRenderer.render(layerBackround); //renders layer in Tiled that p1 covers
game.batch.setProjectionMatrix(cam.combined); //keeps player sprite from doing weird out of sync movement
mouse_position.set(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(mouse_position); //gets mouse coordinates within viewport
game.batch.begin(); //starts sprite spriteBatch
playerOne.renderSprite(game.batch);
game.batch.end(); //starts sprite spriteBatch
//mapRenderer.render(layerAfterBackground); //renders layer of Tiled that hides p1
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true); //updates the viewport camera
}
I solved it by fiddling around with the padding of the tilesets in GDX Texture Packer. I added 5 pixels of padding around the 32x32 tiles. I set the margins to 2, and spacing to 4 in Tiled. I had tried a lot of different combinations of padding/spacing/margins that didn't work which made me think it was a coding problem, but those settings worked, and I didn't have to round the floats.
I am making a game as a project for a college class. when my main character (the tree) hits the ground, it stops short of the ground
screenshot 1
and when the player lands on the little platform that gap is even bigger
screenshot 2
my code for creating the body of the character and and ground is this
public static Body createBody(int x, int y, float width, float height, boolean isStatic){
Body body;
BodyDef def = new BodyDef();
if(isStatic){
def.type = BodyDef.BodyType.StaticBody;
}
else {
def.type = BodyDef.BodyType.DynamicBody;
}
def.position.set(x / PPM , y / PPM);
// returns a World object
body = GlobalWorld.getInstance().createBody(def);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width / 2 / PPM, height / 2 / PPM);
body.createFixture(shape, 1.0f);
shape.dispose();
return body;
}
The code for the ground is in it's own class
public class Material {
private Texture image;
private Body body;
private Sprite sprite;
public Material(Texture t, int x, int y, int w, int h){
image = t;
sprite = new Sprite(t);
body = BoxBuilder.createBody(x, y, w, h, true);
body.setUserData("Ground");
}
public void draw(){
// returns a SpriteBatch
SpriteBatch batch = GlobalBatch.getInstance();
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
batch.begin();
sprite.draw(batch);
batch.end();
}
public void dispose(){
image.dispose();
}
}
the code for drawing the ground
public void draw(){
for(Material m : worldObjects){
m.draw();
}
}
my code for drawing the character
public void create(){
// do stuff
// global vars
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
// do stuff
}
public void render(){
// do stuff
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
batch.begin()
sprite.draw(batch)
batch.end()
// do stuff
}
and PPM(Pixel per Meter) is
public static final float PPM = 32;
I don't know what is the problem here, I want the character to land on the ground, not land above it. So if someone could tell me what's causing this or point me to a good tutorial for learning more about box2d I'd appreciate it.
When we create body with PolygonShape then body is at the center of that Polygon so when draw with body position it starts drawing from center of PolygonShape so we need to draw at left bottom corner.
In Material class
replace
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2,body.getPosition().y-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
And for Character draw also change
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2, body.getPosition().y*PPM-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
As I see in your code you're not setting size of Sprite in Material class as well as for Character so set width and height.
In Material Class
sprite = new Sprite(t);
sprite.setSize(w,h);
And for Character
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
sprite.setSize(313,260);
I'm teaching myself LibGdx and was following the simple game tutorial, unfortunately majority of the code is in one class. I want to refactor the code so I can use multiple textures for the rain that falls based on a random number.
I'll attach the Code for the main program and then the class I got started on.
So far everything worked except the Rain texture/img does not show on the screen.
public class GameScreen implements Screen {
public static FruitHarvest game;
protected final Texture dropImage;
//protected final Texture dropImage2;
private final Texture bucketImage;
public static Rectangle bucket;
public static Sound dropSound;
//private static Music rainMusic;
private final OrthographicCamera camera;
public static Array<Rectangle> raindrops;
private long lastDropTime;
public static int dropsGathered;
// private int random = MathUtils.random(0,1);
private Drops drop;
//Iterator<Rectangle> iterator = raindrops.iterator();
public GameScreen(final FruitHarvest game) {
this.game = game;
// load the images for the droplet and the bucket, 64x64 pixels each
dropImage = new Texture(Gdx.files.internal("droplet.png"));
//dropImage2 = new Texture(Gdx.files.internal("droplet1.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"));
//rainMusic.setLooping(true);
// create the camera and the SpriteBatcher
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// create a Rectangle to logically represent the bucket
bucket = new Rectangle();
bucket.x = 800 / 2 - 64 / 2; // Center the bucket horizontally
bucket.y = 20; // Bottom left corner of the bucket is 20 pixels above the bottom screen edge;
bucket.width = 64;
bucket.height = 64;
// Create the raindrops array and spawn the first raindrop
raindrops = new Array<Rectangle>();
long delta = 0;
drop = new Drops(dropImage, 64, 64, raindrops, delta);
}
#Override
public void render(float delta) {
// 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, .5f, 1);
Gdx.gl.glClear(GL20.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.
game.batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the bucket and all drops
game.batch.begin();
game.font.draw(game.batch, "Drops collected: " + dropsGathered, 0, 480);
game.batch.draw(bucketImage, bucket.x, bucket.y, bucket.width, bucket.height);
// Draws the Items Falling
for (Rectangle raindrop : raindrops) {
game.batch.draw(dropImage, raindrop.x, raindrop.y);
}
game.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 - 64 / 2;
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.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 - 64) bucket.x = 800 - 64;
// check if we need to create a new raindrop
if (TimeUtils.nanoTime() - drop.getLastDropTime() > 1000000000) {
drop.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 increase the value our drops counter
// and add a sound effect.
Iterator<Rectangle> iter = raindrops.iterator();
drop.update(delta);
// while (iter.hasNext()) {
// Rectangle raindrop = iter.next();
// raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
// if (raindrop.y + 64 < 0) iter.remove();
// if (raindrop.overlaps(bucket)) {
// dropsGathered++;
// dropSound.play();
// iter.remove();
// }
// }
}
private void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800 - 64);
raindrop.y = 480;
raindrop.width = 64;
raindrop.height = 64;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
// public void randomDrop(int value, float dropX, float dropY) {
// switch (value) {
// case 0:
// game.batch.draw(dropImage, dropX, dropY);
// break;
// case 1:
// //game.batch.draw(dropImage2, dropX, dropY);
// break;
// default:
// game.batch.draw(dropImage, dropX, dropY);
// break;
// }
// }
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
// start the playback of the background music when the screen is shown
//rainMusic.play();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
//rainMusic.dispose();
}
}
Heres my class for the drops
public class Drops {
private Rectangle raindrop;
private int imageHeight, imageWidth, x, y;
private Array<Rectangle> raindrops;
private long lastDropTime;
private Texture dropImage = new Texture(Gdx.files.internal("droplet.png"));
Iterator<Rectangle> iter = GameScreen.raindrops.iterator();
private float runTime = 0;
public Drops(Texture img, int imageHeight, int imageWidth, Array<Rectangle> drop, float delta) {
this.imageHeight = imageHeight;
this.imageWidth = imageWidth;
this.raindrops = drop;
this.dropImage = img;
}
public void update(float delta) {
while (iter.equals(true)) {
raindrop = iter.next();
raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
if (raindrop.y + 64 < 0) iter.remove();
onCollision();
}
}
public void onCollision() {
if (raindrop.overlaps(bucket)) {
GameScreen.dropsGathered++;
GameScreen.dropSound.play();
iter.remove();
}
}
public void spawnRaindrop() {
Rectangle raindrop = new Rectangle();
raindrop.x = MathUtils.random(0, 800 - 64);
raindrop.y = 480;
raindrop.width = imageWidth;
raindrop.height = imageHeight;
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
public long getLastDropTime() {
return lastDropTime;
}
}
By drop.spawnRaindrop(); you add drops to Array<Rectangle> raindrops; in your Drops class but for drawing you use
for (Rectangle raindrop : raindrops) {
game.batch.draw(dropImage, raindrop.x, raindrop.y);
}
Which will loop trough raindrop array list in your GameScreen which is empty.
So either draw the array list in drops or populate array list in GameScreen.
You need to be more careful as you refactor. You left behind your original Array of drop rectangles in your screen class, and you're drawing that (which is now empty). Then in your Drops class you are referencing the iterator for the now useless array in the screen class. And you're updating that empty array in the screen's render method.
Basically, the drops need to be handled in one place, but you're handling redundant arrays of drops in two different classes and getting them all mixed up.
It's not clear to me why you even have a class called Drops that tries to handle collisions with a bucket. There's no reason to move top-level game logic into a separate class, as that just complicates the code. If you had a more complicated game, it might make sense to have separate classes for tracking and updating various aspects of the game.
Incidentally, you're leaking a texture you load in this line:
private Texture dropImage = new Texture(Gdx.files.internal("droplet.png"));
because you never dispose of it before replacing the reference with another one in the constructor. In LibGDX, any object that implements Disposable must be disposed before its reference is lost, or it will leak native memory.
The straight-forward way to allow multiple drop images:
1) Go back to your original single class with all the game logic in the screen class.
2) Load your drop images into an array for easier access.
private final Array<Texture> dropImages = new Array<Texture>(); // replaces your dropImage declaration
//...
// in constructor:
dropImages.add(new Texture(Gdx.files.internal("droplet.png")));
dropImages.add(new Texture(Gdx.files.internal("droplet1.png")));
// etc. as many variations as you like
// don't forget to dispose of them:
#Override
public void dispose() {
for (Texture dropImage : dropImages) dropImage.dispose();
bucketImage.dispose();
dropSound.dispose();
}
3) Create a class Drop that extends Rectangle and has an additional parameter for the image type. You probably also want to make these sortable by image index to avoid swapping between Textures multiple times as you draw them, which causes batch flushes since you're not using a TextureAtlas.
public class Drop extends Rectangle implements Comparable<Drop>{
public int imageIndex;
public Drop (){
super();
}
public int compareTo(Drop otherDrop) {
return (int)Math.signum(imageIndex - otherDrop.imageIndex);
}
}
4) Change your Array<Rectangle> to Array<Drop>. When you spawn a drop, also give it a random image index:
private void spawnRaindrop() {
Drop raindrop = new Drop ();
raindrop.x = MathUtils.random(0, 800 - 64);
raindrop.y = 480;
raindrop.width = 64;
raindrop.height = 64;
raindrop.imageIndex = MathUtils.random(dropImages.size); // <-- HERE
raindrops.add(raindrop);
lastDropTime = TimeUtils.nanoTime();
}
5) When drawing your drops, use the drop's imageIndex to pull the correct texture. You can sort them first to avoid swapping the Texture back and forth:
// Draws the Items Falling
raindrops.sort();
for (Drop raindrop : raindrops) {
game.batch.draw(dropImages.get(raindrop.imageIndex), raindrop.x, raindrop.y);
}
I'm playing around with some basic OpenGL stuff and I'm trying to set up a simple square with lighting enabled, but the lighting is not correct so there is something wrong with my normals i guess.
Or is my understanding of normals totally wrong?
Here's my rendering code (btw I'm using lwjgl):
public class Renderer {
DisplayMode displayMode;
int i;
int width;
int height;
private boolean drawAxes = false;
private float rotation = 40.0f;
private float zoom = -20f;
// ----------- Variables added for Lighting Test -----------//
private FloatBuffer matSpecular;
private FloatBuffer lightPosition;
private FloatBuffer whiteLight;
private FloatBuffer lModelAmbient;
public Renderer(int width, int height) {
this.width = width;
this.height = height;
}
public static Renderer start() throws LWJGLException {
Renderer r = new Renderer(800, 600);
r.initContext();
r.run();
return r;
}
private void initContext() throws LWJGLException {
Display.setFullscreen(false);
DisplayMode d[] = Display.getAvailableDisplayModes();
for (int i = 0; i < d.length; i++) {
if (d[i].getWidth() == width && d[i].getHeight() == height && d[i].getBitsPerPixel() == 32) {
displayMode = d[i];
break;
}
}
Display.setDisplayMode(displayMode);
Display.create();
}
private void run() {
initGL();
while (!Display.isCloseRequested()) {
preRender();
render();
Display.update();
Display.sync(60);
}
Display.destroy();
}
private void initGL() {
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
GL11.glClearDepth(1.0); // Depth Buffer Setup
GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(45.0f, (float) displayMode.getWidth() / (float) displayMode.getHeight(), 0.1f, 100.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
// Really Nice Perspective Calculations
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
initLightArrays();
glShadeModel(GL_SMOOTH);
glMaterial(GL_FRONT, GL_SPECULAR, matSpecular); // sets specular material color
glMaterialf(GL_FRONT, GL_SHININESS, 100.0f); // sets shininess
glLight(GL_LIGHT0, GL_POSITION, lightPosition); // sets light position
glLight(GL_LIGHT0, GL_SPECULAR, whiteLight); // sets specular light to white
glLight(GL_LIGHT0, GL_DIFFUSE, whiteLight); // sets diffuse light to white
glLightModel(GL_LIGHT_MODEL_AMBIENT, lModelAmbient); // global ambient light
glEnable(GL_LIGHTING); // enables lighting
glEnable(GL_LIGHT0); // enables light0
glEnable(GL_COLOR_MATERIAL); // enables opengl to use glColor3f to define material color
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // tell opengl glColor3f effects the ambient and diffuse properties of material
}
private void preRender() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GL11.glTranslatef(0f, 0f, zoom);
GL11.glRotatef(-60f, 1f, 0f, 0f);
GL11.glRotatef(rotation, 0f, 0f, 1f);
}
private void render() {
FloatBuffer cBuffer = BufferUtils.createFloatBuffer(6*3);
float[] cArray = { 1f,1f,1f,
1f,1f,1f,
1f,1f,1f,
1f,1f,1f,
1f,1f,1f,
1f,1f,1f};
cBuffer.put(cArray);
cBuffer.flip();
FloatBuffer vBuffer = BufferUtils.createFloatBuffer(6*3);
float[] vArray = { 1f,1f,0f,
-1f,-1f,0,
1f,-1f,0,
1f,1f,0f,
-1f,1f,0,
-1f,-1f,0};
vBuffer.put(vArray);
vBuffer.flip();
FloatBuffer nBuffer = BufferUtils.createFloatBuffer(6*3);
float[] nArray = { 0f,0f,1f,
0f,0f,1f,
0f,0f,1f,
0f,0f,1f,
0f,0f,1f,
0f,0f,1f};
nBuffer.put(nArray);
nBuffer.flip();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glColorPointer(3, 0, cBuffer);
glVertexPointer(3, 0, vBuffer);
glNormalPointer(3, nBuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
if (drawAxes) {
drawAxes(6);
}
glTranslatef(0.0f, 0.0f, 3);
glColor3f(0.1f, 0.4f, 0.9f);
}
public static void main(String[] args) throws LWJGLException {
System.setProperty("org.lwjgl.opengl.Display.allowSoftwareOpenGL", "true");
Renderer.start();
}
You are setting your normal pointer wrong:
glColorPointer(3, 0, cBuffer);
glVertexPointer(3, 0, vBuffer);
glNormalPointer(3, nBuffer);
The fixed-function GL might always expects normals to be 3-dimensional vectors, henze the size parameter (which tells the GL how many values are there in every vector) is not present in glNormalPointer. The 3 you are setting here is the stride parameter, which specifies the byte offset between consecutive array elements. Now 3 does not make any sence, it will interpret the second normal as to beginning 3 bytes into the arry, which means it combines the last byte of your first normal's x component together with 3 bytes from your first normal's y component when it reads the second normal'x s component, and so on...
Since your array is tightly packed, you can use the shortcut 0 here, like you do with the other pointers.
However, you must be aware that all of that is deprecated since almost a decade in OpenGL, modern core versions of OpenGL do not support the fixed function pipeline at all. If you are learning OpenGL nowadays, I strongly recommend you to learn modern, shader-based GL instead.
Without seeing more of your code, it's very difficult to see exactly what's going wrong.
However, I do see one thing that could be a problem:
FloatBuffer vBuffer = BufferUtils.createFloatBuffer(6*3);
float[] vArray = { 1f,1f,0f,
1f,-1f,0,
-1f,-1f,0,
1f,1f,0f,
-1f,1f,0,
-1f,-1f,0};
vBuffer.put(vArray);
vBuffer.flip();
The winding order on your triangles are not the same. The first triangle winds clockwise, whereas the second triangle winds counter-clockwise. You'll need to reorder the vertices to make sure that they wind in the same direction. OpenGL usually prefers things to wind counter-clockwise, so if I were you, I'd flip the first triangle.
If you're still getting the problem after you've done this, then post the rest of your draw code, as what you're showing here doesn't give a lot of information.
I call applyEffect in my game logic when the screen is paused, but the image is not set. In its place i get a black background. I instead expect it to show a blurred texture, of the form in image below as expected once I set the gaussian blur shader .
This is sadly the result ;
Why is the screen black?
Here is how i call the method
if (Gdx.input.isKeyPressed(Keys.P) || pause)
{
state = State.GAME_PAUSED;
setBackgroundTexture(applyEffect());
gameScreenGamePauseMenu.sendInMenu();
}
public TextureRegion applyEffect()
{
boolean m_fboEnabled = true;
FrameBuffer m_fbo = null;
float m_fboScaler = 1;
TextureRegion m_fboRegion = null;
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
if(m_fboEnabled) // enable or disable the supersampling
{
if(m_fbo == null)
{
// m_fboScaler increase or decrease the antialiasing quality
m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
m_fboRegion = new TextureRegion(m_fbo.getColorBufferTexture());
m_fboRegion.flip(false, true);
}
m_fbo.begin();
}
if(m_fbo != null)
{
m_fbo.end();
getStage().getBatch().begin();
getStage().getBatch().draw(m_fboRegion, 0, 0, width, height);
getStage().getBatch().end();
}
return m_fboRegion;
}
Iam using Libgdx to make my game