Im new on Box2d got a problem and couldnt solve it.
I want to move my player left and right when the user touch my left and right buttons.
I created a fixture I can move body and fixture but not the player sprite
How can I attach my player sprite to my body ?
and How should I control body because I cant stop it.
I want to find a proper way of controlling player in box2d. I couldnt use setLinerVelocity etc.
this is my codes
public World world;
public Body bplayer;
public Box2DDebugRenderer b2dr;
public Matrix4 cameraBox2D;
PlayScreen
buttonimage.addListener(new ClickListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
bplayer.setLinearVelocity(-5*PPM , 0);
return true;
}
});
world = new World(new Vector2(player.getPosition().x , player.getPosition().y) , false);
b2dr = new Box2DDebugRenderer();
bplayer = createPlayer(player.getPosition().x , player.getPosition().y);
show method
buttonimage.setPosition(160,0);
rightbuttonimage.setPosition(320,0);
pauseimage.setPosition(220,-20);
cameraBox2D = camera.combined.cpy();
Render method
Gdx.gl.glClearColor(0, 0, 2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.setProjectionMatrix(camera.combined);
player.position.y += 500 * Gdx.graphics.getDeltaTime();
sb.begin();
sb.draw(bg, 0, camera.position.y - (camera.viewportHeight/2));
sb.draw(player.sprite, player.getPosition().x , player.getPosition().y);
for (Tube tube : tubes) {
sb.draw(tube.getlefttube(), tube.getposlefttube().x, tube.getposlefttube().y);
sb.draw(tube.getrighttube(), tube.getposrighttube().x, tube.getposrighttube().y);
sb.draw(tube.getLight() , tube.getPoslight().x , tube.getPoslight().y);
}
delta*=speed;
sb.end();
update(delta);
b2dr.render(world , cameraBox2D);
stage.draw();
app.batch.begin();
app.font23.draw(app.batch,"Lights collected :" + dropsGathered , 0, 720);
app.batch.end();
cameraUpdate method
Vector3 position = camera.position;
position.x = player.position.x;
position.y = player.position.y;
camera.position.set(position);
createPlayer method
Body pBody;
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody;
def.position.set(x * PPM, y * PPM );
def.fixedRotation = true;
pBody = world.createBody(def);
return pBody;
update method
world.step(1 / 60f , 6 , 2);
for(int i = 0; i < tubes.size; i++) {
Tube tube = tubes.get(i);
if (camera.position.y - (camera.viewportWidth/2) > tube.getposlefttube().y + tube.getlefttube().getWidth()) {
tube.reposition(tube.getposlefttube().y + ( TUBE_COUNT) );
}
if (tube.collides(player.getBounds())){
app.setScreen(new GameOver(app));
}
if (tube.gathered(player.getBounds())){
dropsGathered++;
}
if (dropsGathered >= 50){
//app.setScreen(new Stage2(app));
}
}
camera.update();
handleInput();
camera.position.y = player.getPosition().y + 300;
player.update(delta);
camera.update();
cameraUpdate(delta);
stage.act(delta);
Do not use the Sprite class. Use the TextureRegion class instead. Sprite is confusingly subclassed from TextureRegion, so when you call batch.draw(sprite, ...) its position and rotation parameters are ignored because it is being treated as a TextureRegion.
You could use a Sprite by calling sprite.draw(batch) but a Sprite is redundant because your Body already has position and rotation parameters.
Use a TextureRegion directly with the SpriteBatch. You can orient it with rotation parameters passed into the draw method.
Related
I am developing a game in AndEngine and I want to attach a sprite to a parallax background (on my main menu) BUT I don't want the sprite to be repeated (which is what is currently happening).
I have tried this (below) which works but I use the sprites in the game so when I come back to the main menu, the sprites will have moved (I tried resetting the sprites but doesn't seem to be working).
Sprite playerCar = new Sprite(playerX, playerY,
mResourceManager.mPlayerCarTextureRegion,
mVertexBufferObjectManager);
playerCar.setRotation(-15);
attachChild(playerCar);
What I want to do is the following:
Define my sprite as normal:
Sprite playerCar = new Sprite(playerX, playerY,
mResourceManager.mPlayerCarTextureRegion,
mVertexBufferObjectManager);
playerCar.setRotation(-15);
Then attach it to my background:
ParallaxBackground menuParallaxBackground = new ParallaxBackground(0,
0, 0);
menuParallaxBackground.attachParallaxEntity(new ParallaxEntity(0,
new Sprite(0, SCREEN_HEIGHT
- mResourceManager.mParallaxLayerRoad.getHeight(),
mResourceManager.mParallaxLayerRoad,
mVertexBufferObjectManager)));
menuParallaxBackground.attachParallaxEntity(new ParallaxEntity(0,
playerCar));
Which also works but the car keeps on repeating which I do not want.
Any help would be appreciated! Thanks.
Problem was because of the onDraw method on the ParallaxEntity class in the ParallaxBackground class. There was a loop around where the sprites get drawn that keeps going until the sprites fill up the width of the screen. I simply created a custom class and removed the while loop so I could use it for my Main Menu.
ParallaxEntity onDraw code before:
public void onDraw(final GLState pGLState, final Camera pCamera, final float pParallaxValue) {
pGLState.pushModelViewGLMatrix();
{
final float cameraWidth = pCamera.getWidth();
final float shapeWidthScaled = this.mAreaShape.getWidthScaled();
float baseOffset = (pParallaxValue * this.mParallaxFactor) % shapeWidthScaled;
while(baseOffset > 0) {
baseOffset -= shapeWidthScaled;
}
pGLState.translateModelViewGLMatrixf(baseOffset, 0, 0);
float currentMaxX = baseOffset;
do {
this.mAreaShape.onDraw(pGLState, pCamera);
pGLState.translateModelViewGLMatrixf(shapeWidthScaled, 0, 0);
currentMaxX += shapeWidthScaled;
} while(currentMaxX < cameraWidth);
}
pGLState.popModelViewGLMatrix();
}
my CustomParallaxEntity onDraw code after (notice the last while loop removed):
public void onDraw(final GLState pGLState, final Camera pCamera,
final float pParallaxValue) {
pGLState.pushModelViewGLMatrix();
{
final float shapeWidthScaled = this.mAreaShape.getWidthScaled();
float baseOffset = (pParallaxValue * this.mParallaxFactor)
% shapeWidthScaled;
while (baseOffset > 0) {
baseOffset -= shapeWidthScaled;
}
pGLState.translateModelViewGLMatrixf(baseOffset, 0, 0);
this.mAreaShape.onDraw(pGLState, pCamera);
pGLState.translateModelViewGLMatrixf(shapeWidthScaled, 0, 0);
}
pGLState.popModelViewGLMatrix();
}
Thanks to the comments on my question for helping me figure out a solution.
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 am using CCDrawNode to create mask type effect (not exactly mask). Everything works well but there is one problem that CCDrawNode only draws square and i want to draw it with custom texture/sprite. Is there any solution to it.
Below is my code of using CCDrawNode
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCLayer *layer = CCLayer::create();
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
layer->addChild(pSprite, 0);
addChild(layer);
//this is the layer that we want to "cut"
CCLayer* layer1 = CCLayerColor::create(ccc4(122, 144, 0, 255), visibleSize.width, visibleSize.height);
this->setTouchEnabled(true);
//we need to create a ccnode, which will be a stencil for ccclipingnode, draw node is a good choice for that
stencil = CCDrawNode::create();
//CCClipingNode show the intersection of stencil and theirs children
CCClippingNode *cliper = CCClippingNode::create(stencil);
cliper->setInverted(true);
cliper->addChild(layer1);
addChild(cliper);
return true;
}
void HelloWorld::ccTouchesMoved(CCSet* touches, CCEvent* event)
{
CCTouch* touch = (CCTouch*)touches->anyObject();
// get start & end location
CCPoint start = touch->getLocationInView();
CCPoint end = touch->getPreviousLocationInView();
// get corrected location
start = CCDirector::sharedDirector()->convertToGL(start);
end = CCDirector::sharedDirector()->convertToGL(end);
//stencil->drawDot(start, 25, ccc4f(0, 0, 0, 255));
stencil->drawSegment(start, end, 25, ccc4f(0, 0, 0, 255));
}
If you want to draw custom texture you should use CCRenderTexture. In order to draw something you should go smthin like this
myRenderTexture->begin();
mySpriteLoadedWithTexture->visit();
myRenderTexture->end();
Also if you want the drawn lines to be smooth you should draw it in loop so that they are placed in equal distance
float distance = ccpDistance(start, end);
for (int i = 0; i < distance; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
m_brush->setPosition(CCPoint(start.x + (difx * delta), start.y + (dify * delta)));
m_brush->visit();
}
Hope it helps
my world is world = new World(new Vector2(0, 0), true); //there is no gravity
and i have walls in the left, right, top bottom of the screen, so elements do not fly off the display.
I have the following code in my render class:
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, 0, 0);
for (Element element : elements) {
element.body.setUserData(element);
element.rect.x = element.body.getPosition().x-16;//16 = half the width of element
element.rect.y = element.body.getPosition().y-16;
if (element.goodOrEvil == 0) {
batch.draw(happyImage, element.rect.x, element.rect.y);
} else if (element.goodOrEvil == 1) {
batch.draw(sadImage, element.rect.x, element.rect.y);
}
} //i draw the elements that i have to fix the bodies to
batch.end();
debugRenderer.render(world, camera.combined);
Iterator<Element> iter = elements.iterator();
//next i set the accelerometer to move the elements, so that i could control them, i need to move all the elements in the same direction, in the same time
while (iter.hasNext()) {
Element element = iter.next();
element.body.setLinearVelocity(Gdx.input.getAccelerometerY() * 50, -Gdx.input.getAccelerometerX() * 50);
}
if (TimeUtils.nanoTime() - lastDropTime > 1000000000)
spawnElement(); // this creates a new element
world.step(1 / 45f, 6, 2);
Here is my spawnElement() class:
private void spawnElement() {
Rectangle elementRect = new Rectangle();
elementRect.x = MathUtils.random(0, 800 - 32);
elementRect.y = 400;
elementRect.width = 32;
elementRect.height = 32;
Element element = new Element(elementRect, (int) elementRect.x % 2);
elements.add(element);
// First we create a body definition
BodyDef bodyDef = new BodyDef();
// We set our body to dynamic, for something like ground which doesnt
// move we would set it to StaticBody
bodyDef.type = BodyType.DynamicBody;
// Set our body's starting position in the world
bodyDef.position.set(elementRect.x, elementRect.y);
// Create our body in the world using our body definition
body = world.createBody(bodyDef);
// Create a circle shape and set its radius to 6
CircleShape circle = new CircleShape();
circle.setRadius(6f);
// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f; // Make it bounce a little bit
// Create our fixture and attach it to the body
Fixture fixture = body.createFixture(fixtureDef);
element.body = body;
lastDropTime = TimeUtils.nanoTime();
}
Now if i set gravity to exist world = new World(new Vector2(-2, -20), true); and comment out this line: element.body.setLinearVelocity(Gdx.input.getAccelerometerY() * 50, -Gdx.input.getAccelerometerX() * 50); the physics works great, but i cannot control my objects. If i leave the code as it is (no gravity and that line in), i can control my objects, but when an element hits the wall, and another element comes, they overlap, and only then start to divide. I need them to hit one another, and remain close, but not overlap at all. Any ideea on how this could be made?
instead of using element.body.setLinearVelocity(Gdx.input.getAccelerometerY() * 50, -Gdx.input.getAccelerometerX() * 50);
i have used this:
Vector2 gravity = new Vector2(Gdx.input.getAccelerometerY() * 50, -Gdx.input.getAccelerometerX() * 50);
world.setGravity(gravity);
And then it answers just like when i set a static gravity, but i change the gravity at every render, with values from my accelerometer
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);