Hello everyone I'm trying to develop a game like Jetpack so i want to set a gravity that normally push down and when the user tap the screen the gravity change it push up. I searched for a week a tutorial that explain how to do that but I didn't find what I search. Someone can explain me how to do that or post a link to a tutorial ?
Thank you !!
main = new Sprite(sX, sY, mainTextureRegion);
main.setScale(1);
main.setFlippedHorizontal(true);
scene.attachChild(main);
mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
final FixtureDef objectFixtureDef = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f);
final Body body = PhysicsFactory.createBoxBody(mPhysicsWorld, main, BodyType.DynamicBody, objectFixtureDef);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(main, body, true, true));
final Vector2 gravity = new Vector2(0, 5f);
mPhysicsWorld.setGravity(gravity);
scene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(float pSecondsElapsed) {
}
#Override
public void reset() {
// TODO Auto-generated method stub
}});
When the user touches the screen, you shouldn't change the gravity because it is not suppose to be done like that.
When he touches the screen, just apply a LinearImpulse (check if it not already at maximum speed) or something like that to make it go upper. The gravity shouldn't change as it should always attract all of your physics objects down. If your change the gravity you change the behavior of all your objects, not only the player one.
EDIT
To have the physics engine to work you have to call the step() method of the PhysicsWorld class at each render. The problem with Andengine is that you don't directly access the render() method as Andengine handle it at all.
So what you have to do is to register a IUpdateHandler on the Engine object that you return in your onLoadEngine() method.
This way the onUpdate() method of the interface will be called at each render and here you can call the step() method to get the physics part to work. The float value tells you about how many seconds elapsed since last render but you don't have to take care of that. The method is called multiple times per second.
Hope it helps.
EDIT 2
I think this should work :
//on the Scene object or on the Engine one
scene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(float pSecondsElapsed) {
mPhysicsWorld.onUpdate(pSecondsElapsed);
}
#Override
public void reset() {}
});
Related
Hey guys so Im making my first app. I know this is a pretty loaded question but Im having a hard time following examples because the script code is different. I am making a 2D platform runner. To start, I created the platforms, environment as well as a majority if not all of the physics. The player at this point is just a circle (just a place holder). The circle can move from left to right and jump. I have now, created an actual player sprite and made animations for walking, jumping and idle. How do I apply the new sprite animations to the current circle placeholder as well as the script? My next step is to go into the animator and start making transitions i guess. Im just not sure how to add the animations to my current script. I knew this was going to be a challenge and if there is any other info you need, please let me know. Thanks so much guys.
This is my "Controls.cs" that is currently attached to my circle player/placeholder. My CheckGround is attached to him. Everything else should be in relation to the platforms he is jumping on and I dont think will change. Again, I have a sprite walking, jumping and idle that I would like to take place of the current circle/placeholder. I need the walking animation to take place when the left and right arrows are pressed, the pump animation to play when the jump button is pressed and idle animation to play when the player is just standing still otherwise. Again, thanks so much guys!
using UnityEngine;
using System.Collections;
public class Controls : MonoBehaviour
{
public Rigidbody2D rb;
public float movespeed;
public float jumpheight;
public bool moveright;
public bool moveleft;
public bool jump;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool onGround;
// Use this for initialization
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.LeftArrow))
{
rb.velocity = new Vector2(-movespeed, rb.velocity.y);
}
if (Input.GetKey(KeyCode.RightArrow))
{
rb.velocity = new Vector2(movespeed, rb.velocity.y);
}
if (Input.GetKey(KeyCode.Space))
{
if (onGround)
{
rb.velocity = new Vector2(rb.velocity.x, jumpheight);
}
}
if (jump)
{
if (onGround)
{
rb.velocity = new Vector2(rb.velocity.x, jumpheight);
}
jump = false;
}
if (moveright)
{
rb.velocity = new Vector2(movespeed, rb.velocity.y);
}
if (moveleft)
{
rb.velocity = new Vector2(-movespeed, rb.velocity.y);
}
}
}
Read about Animation Controller. After you create it you can grab Animator from your gameObject like transform.GetComponent<Animator>()
Later you can blend your animations or just play them. Unity give you even possibility to make input conditions to play your animations so to be honest you don't even have to type too much code.
Definitely use an Animation Controller.
Have a look at this video - I'm following this tutorial at the moment.
https://www.youtube.com/watch?v=I0IVZhHNarg
I have two bodies(A,B). I want B follows A. I can change B position with setTransfrom() function to A position. But I have to change B's position in every frame rate. So I have to use something like contact listener. When I use normal object in Andengine, it has this function below instead of contactlistener.
this.foot = new Rectangle(this.getX(), this.getY(), 8, 10, ResourcesManager.getInstance().vbom){
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
// super.onManagedUpdate(pSecondsElapsed);
this.setPosition(body.getPosition().x*PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT+1,
body.getPosition().y*PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT-15);
}
};
I mean I can set this kind of listener when I am creating it.Is there any option for box2d body? I mean something like that:
this.footBody=PhysicsFactory.createBoxBody(this.mPhysicsWorld, this.foot, BodyType.DynamicBody, footFixtureDef){
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
// super.onManagedUpdate(pSecondsElapsed);
this.setPosition(body.getPosition().x*PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT+1,
body.getPosition().y*PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT-15);
}
};
The poisition updates of physics bodies is managed by the Box2D library. But you can register an additional update handler to your scene and tell the box2D world what you want done during that update.
this.scene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(float pSecondsElapsed) {
// TODO Auto-generated method stub
//Your code to run here!
}
So if you maintain a list of references to the bodies in your world, you should be able to apply forces or set their positions on each tick of the game.
If you want to make sure you update the world before or after the box2D world step, you could event call
mBox2dWorld.onUpdate(pSecondsElapsed);
from within your own update handler, instead of registering the world as an updateHandler itself.
Here are a couple of less practical suggestions as well:
Or to do that the box2D way you could use a joint. I depends on the following behavior you want.
OR... you don't even have object B as part of the Box2D world, perhaps, and just manage the following behavior outside of box2D. Does it need to collide with stuff?
I was trying to make the enemies in my game go up and down; since I'm using a physic body with a Sprite on it I can't use entity modifiers, so I decided give the body a little push using the .setLinearVelocity(float x, float y) method every time its sprite reach a certain point in the screen.
With just one body works great, but I need to have other enemeis (same sprite, different body) spawning every 5 seconds and doing the same thing, but I don't know how to track them... I mean, I don't know how to control if each body reaches the Y location independently from one another...
For example, right now the code is like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
final Sprite rectangle_face = new Sprite(random_x, this.y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face, BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
//I give the body a initial push
rectangle_face_body.setLinearVelocity(0, -5);
//I register an update handler to the sprite to control if it reaches a certain Y value
rectangle_face.registerUpdateHandler(new IUpdateHandler()
{
#Override
public void onUpdate(float pSecondsElapsed)
{
if (rectangle_face.getY() >= y-50)
{
//Here I just use a flag so that later on below I can do the push
MyApp.this.setLinearVelocity = true;
}
}
#Override
public void reset()
{
// TODO Auto-generated method stub
}
});
//Here I register the physic connector and if the flag permits it, I push the body up
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face, rectangle_face_body, true, false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
if(MyApp.this.setLinearVelocity)
{
rectangle_face_body.setLinearVelocity(0, -3);
MyApp.this.setLinearVelocity = false;
}
}
});
this.mscene.attachChild(rectangle_face);
}
With the code like this the first body do what is planned, it moves up and down but as soon as another body pops up, it falls down and the other body goes up because the boolean setLinearVelocity is always set to true, so there is a costant push upwards; when a third body comes in, the second body falls down as well and this last one takes its place going up
With this code I didn't expect much else... but I don't know what else I can try... how can I control this?
Thanks in advance :)
EDIT: Added working code in an anwser below
I suggest you separate the code for the enemy from the code for the update handler. Create a class Enemy that will contain the Sprite and Body, hold your Enemies in an array and override the onUpdate method of your PhysicsWorld so that it goes through the array of Enemies and does what you want to all of them.
Here's a code snippet showing a very simple way of doing this:
mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {}
#Override
public void onUpdate(float pSecondsElapsed) {
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
});
Please note that this may not a very good idea as this code will probably run on a thread different to the one of the physics engine, which could cause all sorts of problems. A better way would be overriding the onUpdate method of PhysicsWorld:
#Override
public void onUpdate(final float pSecondsElapsed) {
super.onUpdate();
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
If you are unsure of what the first snippet means, look up "anonymous inner class".
Ok, here's the final working code (I didn't create a method to check the position or a class for the enemies just because right now I'm just messing around with the mechanics; I'll create a new project when I'm ready to really start):
this.m_PhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
for(int i = 0; i <= MyApp.this.mSpriteCounter; i++)
{
if (rectangle_face[i].getY() >= y-50)
{
final PhysicsConnector spritePhysicsConnector = m_PhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(rectangle_face[i]);
spritePhysicsConnector.getBody().setLinearVelocity(0, -3);
}
}
};
In this code rectangle_face[] is an array of Sprites; each sprite is created like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
rectangle_face[this.mSpriteCounter] = new Sprite(random_x, y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face[this.mSpriteCounter], BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
rectangle_face_body.setLinearVelocity(0, -5);
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face[this.mSpriteCounter], rectangle_face_body, true, false));
this.mscene.attachChild(rectangle_face[this.mSpriteCounter]);
}
That's it, thanks again for the help :)
I was on a roll last night, when I came across the issue of the ButtonSprite. I could have sworn I've done this before - it seems so simple - but using the code that AndEngineExamples provides doesn't really make sense and comes up with errors (for instance - why does a vague "run()" method create the response to every single touch event?).
So I did something that seemed to make sense.
private void loadScenes()
{
mainScene = new Scene();
menu = new Sprite(0, 0, menuTextureRegion, mEngine.getVertexBufferObjectManager()){
#Override
protected void preDraw(GLState pGLState, Camera pCamera)
{
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
};
newgamebutton = new ButtonSprite(25, 200, newgameTextureRegion, mEngine.getVertexBufferObjectManager());
multiplayerbutton = new ButtonSprite(25, 310, multiplayerTextureRegion, mEngine.getVertexBufferObjectManager());
menu.setScale(1.65f);
menu.setPosition((CAMERA_WIDTH - menu.getWidth()) * 0.5f, (CAMERA_HEIGHT - menu.getHeight()) * 0.5f);
mainScene.attachChild(menu);
mainScene.attachChild(newgamebutton);
mainScene.attachChild(multiplayerbutton);
mainScene.registerTouchArea(multiplayerbutton);
mainScene.setTouchAreaBindingOnActionDownEnabled(true);
multiplayerbutton.onAreaTouched(mButtonTouched, multiplayerbutton.getWidth(), multiplayerbutton.getHeight());
if(mButtonTouched.isActionDown()) {
mainScene.detachChild(menu);
mainScene.detachChild(multiplayerbutton);
}
}
It seems to make good sense. When the "multiplayer button" is pressed, it gives you the mButtonTouched, and when that's pressed down... it detaches the menu and multiplayer button. This is obviously just me testing things, and not part of any actual project because I'm just learning, but I get a null pointer exception and the app right closes before displaying the "Menu Scene", which obviously normally works. Also, on various sites it says that I should put "public boolean" before multiplayerbutton, but Eclipse won't have that.
I'm sure you guys have already figured this out, but I'm suuuuuuper new to AndEngine. Thanks for any help, guys!
After looking at the code I believe you wanted to do something like this:
ButtonSprite button = new ButtonSprite(25, 310, multiplayerTextureRegion, mEngine.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if(pTouchEvent.isActionDown()) {
mainScene.detachChild(menu);
mainScene.detachChild(multiplayerbutton);
}
return super.onAreaTouched(pTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
}
};
Your code doesn't work because the last if statement doesn't really make sense - it is checking whether the button is pressed when the method loadScenes() executes. I suggest you read up on anonymous inner classes, it took me a long time to figure out that using them is a valid and useful approach in AndEngine.
Here is a primitive example of a different way of managing buttons:
mScene.setOnAreaTouchListener(new IOnAreaTouchListener() {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, ITouchArea pTouchArea, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if (pTouchArea.equals(button) {
doSomething();
return true;
}
return false;
}
});
Please note that this only works when touching Shapes, if you want to detect touch events outside of Shapes, you need to use IOnSceneTouchListener instead.
I'd have already post this question in the Andengine forum but there are already some questions regarding this topic, some have replies but the ones i want to know don't have any replies yet.
I'm trying to simulate a player jump like in Super Mario Bros. First, I used a simple contact listener to have a boolean value false when contact occurs but the contact occurs with walls grounds, everything. So, I'm now trying to attach another small body to the bottom of player as foot sensor using WeldJoint. But I couldn't achieve that. The WeldJoint wouldn't stick at all. I tried to create the WeldJoint on an update thread, nothing. I tried with the setposition method to update the sensor position with the player's, but it just positions the sensor below ground.
Any suggestions would be appreciated. Here is how i tried to create WeldJoint.
Player and sensor
mPlayer = new AnimatedSprite(100, 150, PlayerTextureRegion);
PlayerBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,mPlayer,BodyType.DynamicBody, PLAYER_FIXTURE_DEF);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mPlayer, PlayerBody, true, true));
mScene.getLastChild().attachChild(mPlayer);
final Shape mSensor= new Rectangle(mPlayer.getX()+4,mPlayer.getY()+mPlayer.getHeight(),10,4);
final Body SensorBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,mSensor,BodyType.DynamicBody, SENSOR_FIXTURE_DEF);
this.mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(mSensor, SensorBody, true, true));
mScene.getLastChild().attachChild(mSensor);
mScene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() { }
#Override
public void onUpdate(final float pSecondsElapsed) {
this.createJoint(PlayerBody,SensorBody);
.......
Joint Method
private void createJoint(Body Anchor, Body Sensor){
final WeldJointDef join = new WeldJointDef();
join.initialize(Anchor,Sensor,Anchor.getWorldCenter());
this.mPhysicsWorld.createJoint(join);
}
Ok, instead of WeldJoint I used RevoluteJoint, without the motor configuration and it works fine now. Just initialize two bodies using revoluteJointDef and they are stuck like weldjoint. For time being I'm going with revoluteJoint to make two bodies as one.