I am using the libgdx framework and trying to repeat a background of spikes forever. The issue I am having is that the texture is moving extremely fast forever, but I want to slow it down. I was looking at a tutorial from Google Code and another user had this same issue. The "supposed" solution was this:
if(scrollTimer>1.0f)
scrollTimer = 0.0f;
scrollTimer = 3f;
This was to make it scroll 3 times faster, so I attempted this and substituted 0.3f instead of 3f, but this makes the background at a standstill.
Here is some relevant code that might help in solving this issue:
public class PlayScreen implements Screen{
final Rectangle upSpikeBounds = new Rectangle(0,0,Gdx.graphics.getWidth() * 2, 25);
final Rectangle downSpikeBounds = new Rectangle(0,Gdx.graphics.getHeight() - 25,Gdx.graphics.getWidth() * 2, 25);
Rectangle blockBounds;
float total_time = 0f;
Sprite spikeUpSprite, spikeDownSprite, spriteBlock;
public PlayScreen(Game game){
batch = new SpriteBatch();
player = new Player(new Vector2(Gdx.graphics.getWidth()/10, Gdx.graphics.getHeight()/2), batch);
stage = new Stage();
this.game = game;
Texture spikeUp = new Texture(Gdx.files.internal("spikes.png"));
Texture spikeDown = new Texture(Gdx.files.internal("spikes.png"));
spikeUp.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
spikeDown.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
spikeUpSprite = new Sprite(spikeUp, 0, 0, Gdx.graphics.getWidth(), 25);
spikeDownSprite = new Sprite(spikeDown, 0, 25, Gdx.graphics.getWidth(), -25);
spikeDownSprite.setPosition(0, Gdx.graphics.getHeight() - 20);
spikeUpSprite.setSize(1200, 25);
spikeDownSprite.setSize(1200, 25);
}
public void render(float deltaTime) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
label.setText("Score: " + player.score);
cam.position.set(player.getPosition().x + Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight () / 2,0);
batch.setProjectionMatrix(cam.combined);
cam.update();
total_time += Gdx.graphics.getDeltaTime();
if (total_time > 1.0f){
total_time = 0.0f;
}
spikeUpSprite.setU(total_time);
spikeUpSprite.setU2((total_time+1));
spikeDownSprite.setU(total_time);
spikeDownSprite.setU2(total_time+1);
stage.act();
batch.begin();
spikeUpSprite.draw(batch);
spikeDownSprite.draw(batch);
batch.end();
stage.draw();
}
}
Can anyone help me?
You should look up the tween engine, it will enable you to use 'tween animation', which is an animation of values, who with a duration. For instance if you animate from zero to 700 with a 700ms duration, the value will start from zero and increase by 1 every ms
While micnubinub's answer is certainly interesting and worth checking out, I have figured out a quick fix for my issue. The problem lies in this line:
total_time += Gdx.graphics.getDeltaTime();
This is where the speed of the background lies. Because delta time is so fast (probably to the microsecond), the background scrolls by too fast. If I change it to a manual number, such as 0.0093f, I get a background that scrolls at the speed I desire.
Related
I'm creating two textures and put them in the same TextureAtlas as shown in the code:
public void create () {
pix = new Pixmap(100, 100, Pixmap.Format.RGBA8888);
textureAtlas = new TextureAtlas();
pix.setColor(Color.WHITE);
pix.fill();
textureAtlas.addRegion("white", new TextureRegion(new Texture(pix)));
pix.setColor(Color.RED);
pix.fill();
textureAtlas.addRegion("red", new TextureRegion(new Texture(pix)));
tr_list = textureAtlas.getRegions();
pix.dispose()
}
and then when rendering:
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
for (int i = 0; i < 200; ++i) {
batch.draw(tr_list.get(i % tr_list.size), (int)(Math.random()* 500), (int)(Math.random()* 500));
}
font.draw(batch, "FPS: " + Integer.toString(Gdx.graphics.getFramesPerSecond()), 0, Gdx.graphics.getHeight() - 20);
font.draw(batch, "Render Calls: " + Integer.toString(batch.renderCalls), 0, Gdx.graphics.getHeight() - 60);
batch.end();
}
I was expecting batch.renderCalls to be equal to 1, since the textures are in the same TextureAtlas, but instead it's equal to 200. What am I doing wrong?
In order to draw your TextureRegions in a single render call, each of them must be a part of the same Texture, not TextureAtlas.
TextureAtlas can contain TextureRegions of different Textures, which actually happens in your case. Even though you use the same Pixmap, you create two different Textures from it.
You are drawing them in loop 200 times.
for (int i = 0; i < 200; ++i) {
// this will be called 200 times
batch.draw(tr_list.get(i % tr_list.size), (int)(Math.random()* 500), (int)(Math.random()* 500));
}
And also TextureAtlas class doesn't create pig picture of textures that you add to it. It is just container of TextureRegions how #Arctic23 noticed.
So main problem for you is to draw 2 textures in one render call. I wouldn't recommend you doing this. It is possible but it will be hard to work with them.
Calling batch.draw(..) every time you draw a texture is not a big performance problem. So i don't know why you detach this.
Evening Everyone,
I am attempting to get familiar with libdgx and android by going thru the tutorial Here. All seems good except for grabbing the screen coordinates as they get skewed in a Vector3 conversion.
So x input of 101 gets converted to -796, y input of 968 converted to -429 (touching the upper left corner of the screen, same results from emulator as from my phone). When clicking the bottom right corner, the animation fires in the middle of the screen.
It all seems pretty basic so not really sure what I am setting incorrectly to get a skewed conversion. Any help is appreciated!
camera creation:
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(camera.viewportWidth * .5f, camera.viewportHeight * .5f, 0f);
Grabbing touch coord:
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
touchCoordinateX = screenX;
touchCoordinateY = screenY;
stateTime = 0;
explosionHappening = true;
return true;
}
Render loop:
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stateTime += Gdx.graphics.getDeltaTime();
batch.begin();
if (!explosionAnimation.isAnimationFinished(stateTime) && explosionHappening) {
Vector3 touchPoint = new Vector3();
touchPoint.set(touchCoordinateX,touchCoordinateY,0);
TextureRegion currentFrame = explosionAnimation.getKeyFrame(stateTime, false); // #16
camera.unproject(touchPoint);
batch.draw(currentFrame, touchPoint.x, touchPoint.y);
}
// batch.draw(img, 0, 0);
batch.end();
if (explosionAnimation.isAnimationFinished(stateTime)){explosionHappening = false;}
}
I think you forgot to set camera projection matrix to your SpriteBatch. Just add
batch.setProjectionMatrix(camera.combined);
before
batch.begin();
I´m new with libgx and i have a basic question. I want an background like an image that repeats indefinetely, and moves down. I did with 2 images and it worked, but the problem is that is very slow. I stored the images with 512x512px.
My code is very simple but i dont know what im doing wrong.
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
offset -= 600 * Gdx.graphics.getDeltaTime();
offset = offset % 512;
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(backgroundImage, 0, offset);
batch.draw(backgroundImage, 0, offset + 512);
batch.draw(bucketImage, 0, offset + 1024);
batch.end();
}
Any suggestions will be appreciated
Thanks a lot!
I don't see any reason your render method would cause a slowdown, are you sure the slowdown is happening there? I would bet it's not. Narrow down the root cause of the slowdown which is probably somewhere else in your code.
(I didn't have enough reputation to comment)
this is a bug that has been troubling and demotivating me for several days now. Perhaps someone has some insight.
I build a terrain mesh programmatically and set up a renderable for it, with a material that has a texture attribute with a repeating texture created from a PNG file. All of this appears to work fine until the camera is moved for a while, along, say, the x or z axes, at which time the texture will initially flicker to black, and eventually stay black, if the camera is moved far enough away.
I clear the screen with blue – so the mesh is still getting rendered, just without the texture – so it is solid black. This happens at the same spots with regards to camera placement. Once the camera is far enough away, the problem persists if the camera continues to move away from the world origin.
The problem does not appear on desktop, only android. I am using an HTC EVO 4G to test. I realize that this phone's early Adreno GPU has some serious 3D issues, but I've surely seen games, or at least demos, with large textured landscapes work fine. My mesh has around 5000 triangles and usually renders around 30-40 fps.
Some things I have experimented with:
Change PNG compression to 0 in the GIMP export options
Used JPG instead of PNG
Explictly specifying no mipmapping
Changed filtering modes
PNG files of different sizes and resolutions
Check glGetError
Here is the relevant code:
private void createMesh(){
mesh = new Mesh(true, vertices.length, indices.length,
new VertexAttribute(Usage.Position, 3, "a_position"),
new VertexAttribute(Usage.Normal, 3, "a_normal"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
float vertexData[] = new float[vertices.length * 8];
for (int x = 0; x < vertices.length; x++) {
vertexData[x*8] = vertices[x].position.x;
vertexData[x*8+1] = vertices[x].position.y;
vertexData[x*8+2] = vertices[x].position.z;
vertexData[x*8+3] = vertices[x].normal.x;
vertexData[x*8+4] = vertices[x].normal.y;
vertexData[x*8+5] = vertices[x].normal.z;
vertexData[x*8+6] = vertices[x].texCoord.x;
vertexData[x*8+7] = vertices[x].texCoord.y;
}
mesh.setVertices(vertexData);
mesh.setIndices(indices);
}
The texture repeats across the terrain, but I've commented out the setWrap line before and the problem
persists.
private void createRenderable(Lights lights){
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
TextureAttribute textureAttribute1 = new TextureAttribute(TextureAttribute.Diffuse, texture);
terrain = new Renderable();
terrain.mesh = mesh;
terrain.worldTransform.trn(-xTerrainSize/2, (float) -heightRange, -zTerrainSize/2);
terrain.meshPartOffset = 0;
terrain.meshPartSize = mesh.getNumIndices();
terrain.primitiveType = GL10.GL_TRIANGLE_STRIP; // or GL_TRIANGLE_STRIP etc.
terrain.material = new Material(textureAttribute1);
terrain.lights = lights;
}
Note that decreasing the far clipping plane does not make a difference.
...
lights = new Lights();
lights.ambientLight.set(0.2f, 0.2f, 0.2f, 1f);
lights.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
cam = new PerspectiveCamera(90, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0, 0, 0);
cam.lookAt(0,0,-1);
cam.near = 0.1f;
cam.far = 1000f;
cam.update();
...
#Override
public void render () {
...
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.graphics.getGL10().glClearColor( 0, 0, 1, 1 );
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(terrain);
modelBatch.end();
...
}
Any insight into this problem would be much-appreciated. Unfortunately, it is difficult to screen capture on an EVO 4G, or else I would post a picture.
I am working on CoCos2d with android.I want to add an endless scrolling background to my Screen by using CCParallaxNode.
I am able to add background and move it but after the completion of that move action the screen goes black.
Can someone help me out?
My code is
CCParallaxNode parallaxNode;
CCSprite spacedust1;
CCSprite spacedust2;
CCSprite planetsunrise;
CCSprite galaxy;
CCSprite spacialanomaly;
CCSprite spacialanomaly2;
parallaxNode = CCParallaxNode.node();
spacedust1 = CCSprite.sprite("bg_front_spacedust.png");
spacedust2 = CCSprite.sprite("bg_front_spacedust.png");
planetsunrise = CCSprite.sprite("bg_planetsunrise.png");
galaxy = CCSprite.sprite("bg_galaxy.png");
spacialanomaly = CCSprite.sprite("bg_spacialanomaly.png");
spacialanomaly2 = CCSprite.sprite("bg_spacialanomaly2.png");
// 3) Determine relative movement speeds for space dust and background
// CGPoint cgPoint = CGPoint.ccp(0.1, 0.1);
CGPoint dustSpeed = CGPoint.ccp(10, 10);
CGPoint bgSpeed = CGPoint.ccp(5, 5);
// CGPoint bgSpeed = ccp(0.05, 0.05);
parallaxNode.addChild(spacedust1, 0, dustSpeed.x, dustSpeed.y, 0,
winSize.height / 2);
parallaxNode.addChild(spacedust2, 0, dustSpeed.x, dustSpeed.y,
spacedust1.getContentSize().width, winSize.height / 2);
parallaxNode.addChild(galaxy, -1, bgSpeed.x, bgSpeed.y, 0, 10);
parallaxNode.addChild(planetsunrise, -1, bgSpeed.x, bgSpeed.y, 600, 5);
parallaxNode
.addChild(spacialanomaly, -1, bgSpeed.x, bgSpeed.y, 900, 20);
parallaxNode.addChild(spacialanomaly2, -1, bgSpeed.x, bgSpeed.y, 1500,
30);
CCIntervalAction go = CCMoveBy.action(4, CGPoint.ccp(winSize.width, 0));
CCIntervalAction goBack = go.reverse();
CCIntervalAction seq = CCSequence.actions(go, goBack);
CCRepeatForever action = CCRepeatForever.action(goBack);
parallaxNode.runAction(action);
I see that since not a single answer worked for you. I will provide a simple code which will help you for your parralax scrolling background.
Add this code in your game layers constructor
background1 = CCSprite.sprite("bg2.png");
background2 = CCSprite.sprite("bg2.png");
background1.setPosition(CGPoint.ccp(winSize.width*0.5f,winSize.height*0.5f));
addChild(background1);
background2.setPosition(CGPoint.ccp(winSize.width+winSize.width*0.5f,winSize.height*0.5f));
addChild(background2);
and a scroll method which is scheduled every millisecond.
add this in constructor
this.schedule("scroll");
and now the scroll method.
public void scroll(float dt) {
CGPoint pos1 = background1.getPosition();
CGPoint pos2 = background2.getPosition();
pos1.x -= 5.0f;
pos2.x -= 5.0f;
if(pos1.x <=-(winSize.width*0.5f) )
{
pos1.x = pos2.x + winSize.width;
}
if(pos2.x <=-(winSize.width*0.5f) )
{
pos2.x = pos1.x + winSize.width;
}
background1.setPosition(pos1);
background2.setPosition(pos2);
}
mark my answer if it worked.
Call this method from the class Constructor. I found this trick from Example : "shotingblock-master" available on github...
private void endlessBackground() {
// Create the two background sprites which will alternate
_oddBackground = CCSprite.sprite("blue_background.png");
_evenBackground = CCSprite.sprite("blue_background.png");
// One starts dead centre and one starts exactly one screen height above
oddBackground.setPosition(_winSize.width / 2, _winSize.height / 2);
evenBackground.setPosition(_winSize.width / 2, _winSize.height
+ (_winSize.height / 2));
// Schedule the scrolling action
schedule("scroll");
// Add sprites to the layer
addChild(_oddBackground).addChild(_evenBackground);
}
public void scroll(float dt) {
// move them 100*dt pixels down
_oddBackground.setPosition(_oddBackground.getPosition().x,
_oddBackground.getPosition().y - 150 * dt);
_evenBackground.setPosition(_evenBackground.getPosition().x,
_evenBackground.getPosition().y - 150 * dt);
// reset position when they are off from view.
if (_oddBackground.getPosition().y < -_winSize.height / 2) {
_oddBackground.setPosition(_winSize.width / 2, _winSize.height / 2);
_evenBackground.setPosition(_winSize.width / 2, _winSize.height
+ (_winSize.height / 2));
}
}
}
IT works excellent in my case. May be it'll help full for you.
try using this:
CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage("pic.png");
ccTexParams params = {GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT};
texture->setTexParameters(¶ms);
CCSprite *sprite = CCSprite::spriteWithTexture(texture, CCRectMake(0, 0, 90, 90));
and make sure that The image's height and width must be power of 2.
It looks like the CCRepeatForever action is only running it goBack, which means that it's not reversing. Try the following:
CCIntervalAction go = CCMoveBy.action(4, CGPoint.ccp(winSize.width, 0));
CCIntervalAction goBack = go.reverse();
CCIntervalAction seq = CCSequence.actions(go, goBack);
CCRepeatForever action = CCRepeatForever.action(seq); // change to seq instead of goBack
parallaxNode.runAction(action);
This is trick for make it happen. You can Use the large png and working on it or check the sample test code which is available in coocs2d-android library
CCSprite background = CCSprite.sprite("background.png");
// create a void node, a parent node
CCParallaxNode voidNode = CCParallaxNode.node();
// background image is moved at a ratio of 0.4x, 0.5y
voidNode.addChild(background, -1, 0.4f, 0.5f, 0, 0);
// write your own code for the parallax node
CCIntervalAction goUp = CCMoveBy.action(4, CGPoint.make(0,-200));
CCIntervalAction goDown = goUp.reverse();
CCIntervalAction go = CCMoveBy.action(8, CGPoint.make(-1000, 0));
CCIntervalAction goBack = go.reverse();
CCIntervalAction seq = CCSequence.actions(goUp, go, goDown, goBack);
voidNode.runAction(CCRepeatForever.action(seq));
addChild(voidNode);
Please check out below link for Parallax vertical endless background:
http://kalpeshsantoki.blogspot.in/2014/07/create-vertical-endless-parallax.html
CGSize winSize = CCDirector.sharedDirector().displaySize();
//I made graphics for screen 720*1200....so I made this dynamic scale to support multiple screens
float sX = winSize.width / 720.0f;
float sY = winSize.height / 1200.0f;
background = CCVerticalParallaxNode.node(sX, sY, true);
background.addEntity(1f, "background.png", 0);
background.addEntity(3, "road_simple.png", winSize.width / 2);
background.addEntity(1.7f, "road_side.png", 0);
addChild(background);