افزودن دیدگاه جدید

Revolute Joint

Revolute Joint در andengine که در حقیقت بخشی از box2d است یکی از پرکاربردترین انواع joint است و می توان آن را به عنوان لولا ، محور یا سنجاق که دو شی (body) را به هم متصل می کند در نظر گرفت ، برای هر کدام از اشیا میتوان محل اتصال (anchor point) را مشخص کرد تا دقیقاً در یک نقطه خاص به هم وصل شوند ، به علاوه به صورت اختیاری می توان برای این انوع اتصال یک موتور و حد نیز تعیین کرد ، با اعمال Torque به موتور می توان شی مورد نظر را به حرکت در آورد و در صورتی که این Torque به اندازه کافی زیاد باشد باعث چرخش شی می شود.

با اعمال حد (limit) های بالا و پایین می توان کاری کرد که شی مورد چرخش فقط تا یک زاویه خاص قابلیت جا به جایی داشته باشد.(به عنوان مثال شما دوست نخواهید داشت که بازوی یک بیل مکانیکی 360 درجه چرخش داشته باشد!)

Revolute Joint را می توان به صورت زیر تصور کرد :

anchor جایی است که دو شی به هم متصل می شوند و در ادامه یاد می گیریم که چگونه جای دقیق آن را در هر دو شی (body) مشخص کنیم.

motor باعث حرکت (و یا حتی چرخش) شی دوم می شود

حدود lowerAngle و upperAngle باعث می شوند که شی دوم آزادی عمل صد در صد نداشته باشد و فقط تا حدود مشخص شده حرکت کند.

از Revolute Joint می توان برای ساخت چرخ ، غلتک ، زنجیر ، پل معلق ، لولا ، اهرم ، منجنیق ، بدن یک عروسک و ... استفاده کرد و کاربرد های آن بسته به خلاقیت برنامه نویس بسیار زیاد است.

در ادامه به صورت عملی با این joint آشنا می شویم.

مثل همیشه یک کد کامل و قابل اجرا می نویسیم تا درک بهتر و عملی تری از موضوع داشته باشیم :


package com.safecomp.andenginetutone;

import java.io.IOException;

import org.andengine.engine.Engine;
import org.andengine.engine.FixedStepEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.ui.activity.BaseGameActivity;

import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;

public class RevoluteJointExample extends BaseGameActivity {
	private Camera pCamera;
	Scene pScene;
	private static final int CAMERA_WIDTH = 720;
	private static final int CAMERA_HEIGHT = 480;

	Rectangle rectA;
	Rectangle rectB;

	Body bodyA;
	Body bodyB;

	FixtureDef fixture;

	PhysicsWorld pPhysicsWorld;

	RevoluteJointDef revoluteJointDef;

	@Override
	public Engine onCreateEngine(EngineOptions pEngineOptions) {
		return new FixedStepEngine(pEngineOptions, 60);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		pCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions eo = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), pCamera);
		return eo;
	}

	@Override
	public void onCreateResources(
			OnCreateResourcesCallback pOnCreateResourcesCallback)
			throws IOException {
		pOnCreateResourcesCallback.onCreateResourcesFinished();
	}

	@Override
	public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
			throws IOException {
		pScene = new Scene();
		pScene.setBackground(new Background(0, .7f, .7f));

		pPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0f,
				-SensorManager.GRAVITY_EARTH * 2), false, 8, 3);

		fixture = PhysicsFactory.createFixtureDef(20, .2f, .9f);

		rectA = new Rectangle(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, 40, 40,
				getVertexBufferObjectManager());
		rectA.setColor(1, 0, 0);

		pScene.attachChild(rectA);

		bodyA = PhysicsFactory.createBoxBody(pPhysicsWorld, rectA,
				BodyType.KinematicBody, fixture);

		rectB = new Rectangle(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2 + 60, 40, 40,
				getVertexBufferObjectManager());
		rectB.setColor(0, 1, 0);

		pScene.attachChild(rectB);

		bodyB = PhysicsFactory.createBoxBody(pPhysicsWorld, rectB,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectB,
				bodyB));

		revoluteJointDef = new RevoluteJointDef();
		revoluteJointDef.initialize(bodyA, bodyB, bodyA.getWorldCenter());
		revoluteJointDef.enableMotor = true;
		revoluteJointDef.motorSpeed = -1;
		revoluteJointDef.maxMotorTorque = 5000;

		RevoluteJoint rj = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef);

		pScene.registerUpdateHandler(pPhysicsWorld);
		pOnCreateSceneCallback.onCreateSceneFinished(pScene);
	}

	@Override
	public void onPopulateScene(Scene pScene,
			OnPopulateSceneCallback pOnPopulateSceneCallback)
			throws IOException {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

}

خروجی به صورت زیر خواهد بود :

کد های زیر بخش مهم کد قبلی هستند :


		revoluteJointDef = new RevoluteJointDef();
		revoluteJointDef.initialize(bodyA, bodyB, bodyA.getWorldCenter());
		revoluteJointDef.enableMotor = true;
		revoluteJointDef.motorSpeed = -1;
		revoluteJointDef.maxMotorTorque = 5000;

		RevoluteJoint rj = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef);


bodyA و bodyB دو شی ای هستند که قصد داریم آن ها را به هم متصل کنیم ، rectA و rectB برای تعیین شکل ظاهری bodyA و bodyB استفاده می شوند ، از revoluteJointDef برای تعریف joint استفاده می کنیم.

با استفاده از متد initialize مشخص می کنیم که میخواهیم دو شی bodyA و bodyB به هم متصل شوند و bodyB حول bodA بچرخد.

enableMotor را برابر با true قرار می دهیم تا بتوانیم شی bodyB را به حرکت در بیارویم.

motorSpeed منفی باعث می شود که شی در جهت عقربه های ساعت بچرخد.

maxMotorTorque را برابر با یک مقدار بسیار بزرگ قرار می دهیم تا چرخش کامل و 360 درجه انجام شود.

پس از اینکه متد createJoint را فراخوانی کردیم نتیجه آن را در rj ذخیره می کنیم ، اگر بعداً بخواهید در حین اجرای بازی ویژگی های joint را تغییر دهید باید از rj استفاده کنید (بسیاری از برنامه نویسان مبتدی revoluteJointDef را تغییر می دهند و به مشکل بر می خورند ، در صورتی که revoluteJointDef  فقط برای تعریف اولیه باید استفاده شود و در زمان اجرا باید از rj استفاده کنید)

 

َAnchor :

در ابتدای مطلب گفتم که با استفاده از anchor point می توانیم دقیقاً مشخص کنیم که دو شی از چه نقطه ای به هم متصل شوند ، در چنین مواقعی بهتر است همه چیز را از قبل روی کاغذ رسم کنید و پس از محاسبه نقطه اتصال و ... کد لازم را بنویسید ،مثال ساده زیر را در نظر بگیرید :

می خواهیم اتصال در نقطه آبی رنگ صورت گیرد ، شی A به طول 200 و شی B به طول صد است ، میخواهیم اتصال در وسط لبه سمت راست این دو شکل انجام گیرد .

برای تعیین نقاط اتصال باید از localAnchorA برای شی اول و localAnchorB برای شی دوم استفاده کنیم ، به صورت پیش فرض این دو نقطه به وسط شی اشاره می کنند که چون مقدار دهی ها نسبی است و از وسط اشیا تعریف می شود لذا localAnchor ها ابتدا برابر با 0و0 و یا همان مرکز شکل هستند. میخواهیم این نقاط به وسط لبه سمت راست تغییر کنند پس باید برای شی اول به مختصات x از localAnchorA صد واحد اضافه کنیم. (چون آدرس دهی از وسط تعریف می شود) ، به مختصات y چیزی اضافه نمی کنیم و آن را همان صفر (وسط لبه) در نظر می گیریم.

برای شی دوم نیز باید به مختصات x از localAnchorB پنجاه واحد اضافه کنیم.

به عباراتی دو شی باید در نقاطی که در شکل مشخص شده به هم وصل شوند :

با توجه به توضیحات فوق آماده ایم تا کد قبل را به صورت زیر تغییر دهیم و در عمل بهتر این موضوع را درک کنیم :


package com.safecomp.andenginetutone;

import java.io.IOException;

import org.andengine.engine.Engine;
import org.andengine.engine.FixedStepEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
import org.andengine.ui.activity.BaseGameActivity;

import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;

public class RevoluteJointExample extends BaseGameActivity {
	private Camera pCamera;
	Scene pScene;
	private static final int CAMERA_WIDTH = 720;
	private static final int CAMERA_HEIGHT = 480;

	Rectangle rectA;
	Rectangle rectB;

	Body bodyA;
	Body bodyB;

	FixtureDef fixture;

	PhysicsWorld pPhysicsWorld;

	RevoluteJointDef revoluteJointDef;

	@Override
	public Engine onCreateEngine(EngineOptions pEngineOptions) {
		return new FixedStepEngine(pEngineOptions, 60);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		pCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions eo = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), pCamera);
		return eo;
	}

	@Override
	public void onCreateResources(
			OnCreateResourcesCallback pOnCreateResourcesCallback)
			throws IOException {
		pOnCreateResourcesCallback.onCreateResourcesFinished();
	}

	@Override
	public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
			throws IOException {
		pScene = new Scene();
		pScene.setBackground(new Background(0, .7f, .7f));

		pPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0f,
				-SensorManager.GRAVITY_EARTH * 2), false, 8, 3);

		fixture = PhysicsFactory.createFixtureDef(20, .2f, .9f);

		rectA = new Rectangle(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, 200, 40,
				getVertexBufferObjectManager());
		rectA.setColor(1, 0, 0);

		pScene.attachChild(rectA);

		bodyA = PhysicsFactory.createBoxBody(pPhysicsWorld, rectA,
				BodyType.KinematicBody, fixture);

		rectB = new Rectangle(CAMERA_WIDTH / 2 + 100, CAMERA_HEIGHT / 2, 100,
				40, getVertexBufferObjectManager());
		rectB.setColor(0, 1, 0);

		pScene.attachChild(rectB);

		bodyB = PhysicsFactory.createBoxBody(pPhysicsWorld, rectB,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectB,
				bodyB));

		revoluteJointDef = new RevoluteJointDef();

		revoluteJointDef.initialize(bodyA, bodyB, bodyA.getWorldCenter());
		
		float xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorA.set(xa, 0);

		float xb = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorB.set(xb, 0);

		revoluteJointDef.enableMotor = true;
		revoluteJointDef.motorSpeed = -1;
		revoluteJointDef.maxMotorTorque = 5000;

		RevoluteJoint rj = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef);

		pScene.registerUpdateHandler(pPhysicsWorld);
		pOnCreateSceneCallback.onCreateSceneFinished(pScene);
	}

	@Override
	public void onPopulateScene(Scene pScene,
			OnPopulateSceneCallback pOnPopulateSceneCallback)
			throws IOException {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

}

ابتدا دقت کنید که اندازه دو شکل را تغییر داده ایم (مبتنی بر مثال تصویری ابعاد آن ها را 200 در 40 و 100 در 40 قرار دادیم).

قسمت مهم کد فوق خطوط زیر است :


		
		float xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorA.set(xa, 0);

		float xb = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorB.set(xb, 0);

	

میخوهیم نقطه اتصال شی اول در نقطه 100 و 0 و نقطه اتصال شی دوم در نقطه 50 و 0 باشد که برای اینکار بایدی localAnchorA و localAnchorB را تغییر دهیم ، ولی مقدار این دو متغیر از نوع Vector2 است ، در دنیای بازی سازی Vecotr2 یک داده خام بدون واحد (unit) است و مشخص نمی کند که مقدار آن مکان است (بر حسب متر) ، سرعت است (بر حسب متر بر ثانیه) یا چیز دیگر! لذا خودمان باید هنگام استفاده از Vector2 دقت کافی داشته باشیم ، در اینجا میخواهیم نقاط اتصال به اندازه 50 و 100 واحد جا به جا شوند که این مقادیر بر حسب مکان (با معیار متر) هستند ، لذا با تقسیم آن ها بر PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT آن ها را به مقادیر مناسب تبدیل می کنیم.(این تبدیل بسیار بسیار اساسی و لازم است و دقت کنید هنگام ساخت بازی آن را فراموش نکنید)

خروجی کد قبل به صورت زیر خواهد بود :

اتصال چند شی :

با استفاده از revolute joint می توانیم یک شی را به چند شی دیگر وصل کنیم و از این طریق اشکال پیچیده و مختلفی ایجاد کنیم ، در مثال زیر شی سومی به مجموعه قبل اضافه می کنیم.البته هر revolute joint تنها دو شی را به هم متصل می کند ولی یک شی می تواند در چند revolute joint شرکت کند ، پس برای هر اتصال به یک revolute joint جداگانه نیاز داریم.(در کد زیر متوجه این موضوع خواهید شد)


package com.safecomp.andenginetutone;

import java.io.IOException;

import org.andengine.engine.Engine;
import org.andengine.engine.FixedStepEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
import org.andengine.ui.activity.BaseGameActivity;

import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;

public class RevoluteJointExample extends BaseGameActivity {
	private Camera pCamera;
	Scene pScene;
	private static final int CAMERA_WIDTH = 720;
	private static final int CAMERA_HEIGHT = 480;

	Rectangle rectA;
	Rectangle rectB;
	Rectangle rectC;

	Body bodyA;
	Body bodyB;
	Body bodyC;

	FixtureDef fixture;

	PhysicsWorld pPhysicsWorld;

	RevoluteJointDef revoluteJointDef;
	RevoluteJointDef revoluteJointDef2;

	@Override
	public Engine onCreateEngine(EngineOptions pEngineOptions) {
		return new FixedStepEngine(pEngineOptions, 60);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		pCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions eo = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), pCamera);
		return eo;
	}

	@Override
	public void onCreateResources(
			OnCreateResourcesCallback pOnCreateResourcesCallback)
			throws IOException {
		pOnCreateResourcesCallback.onCreateResourcesFinished();
	}

	@Override
	public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
			throws IOException {
		pScene = new Scene();
		pScene.setBackground(new Background(0, .7f, .7f));

		pPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0f,
				-SensorManager.GRAVITY_EARTH * 2), false, 8, 3);

		fixture = PhysicsFactory.createFixtureDef(20, .2f, .9f);

		rectA = new Rectangle(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, 200, 40,
				getVertexBufferObjectManager());
		rectA.setColor(1, 0, 0);

		pScene.attachChild(rectA);

		bodyA = PhysicsFactory.createBoxBody(pPhysicsWorld, rectA,
				BodyType.KinematicBody, fixture);

		rectB = new Rectangle(CAMERA_WIDTH / 2 + 100, CAMERA_HEIGHT / 2, 100,
				40, getVertexBufferObjectManager());
		rectB.setColor(0, 1, 0);

		pScene.attachChild(rectB);

		bodyB = PhysicsFactory.createBoxBody(pPhysicsWorld, rectB,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectB,
				bodyB));

		rectC = new Rectangle(CAMERA_WIDTH / 2 - 100, CAMERA_HEIGHT / 2, 100,
				40, getVertexBufferObjectManager());
		rectC.setColor(0, 0, 1);

		pScene.attachChild(rectC);

		bodyC = PhysicsFactory.createBoxBody(pPhysicsWorld, rectC,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectC,
				bodyC));

		// revolute joint bodyA and bodyB
		revoluteJointDef = new RevoluteJointDef();

		revoluteJointDef.initialize(bodyA, bodyB, bodyA.getWorldCenter());

		float xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorA.set(xa, 0);

		float xb = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorB.set(xb, 0);

		revoluteJointDef.enableMotor = true;
		revoluteJointDef.motorSpeed = -1;
		revoluteJointDef.maxMotorTorque = 5000;

		RevoluteJoint rj = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef);

		// revolute joint bodyA and bodyC
		revoluteJointDef2 = new RevoluteJointDef();

		revoluteJointDef2.initialize(bodyA, bodyC, bodyA.getWorldCenter());

		xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef2.localAnchorA.set(-xa, 0);

		float xc = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef2.localAnchorB.set(xc, 0);

		revoluteJointDef2.enableMotor = true;
		revoluteJointDef2.motorSpeed = 1;
		revoluteJointDef2.maxMotorTorque = 5000;

		RevoluteJoint rj2 = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef2);

		pScene.registerUpdateHandler(pPhysicsWorld);
		pOnCreateSceneCallback.onCreateSceneFinished(pScene);
	}

	@Override
	public void onPopulateScene(Scene pScene,
			OnPopulateSceneCallback pOnPopulateSceneCallback)
			throws IOException {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

}

خروجی :

یک مثال دیگر :

در مثال های قبل یکی از اشیا از نوع KinematicBody بود ، این کار را انجام دادیم تا یکی از اشیا در صفحه دیگر اشیا را نگه دارد و اشیا بر اثر جاذبه به پایین نیفتند و از صفحه خارج نشوند ، در ادامه کد را به شکلی تغییر می دهیم که همه اشیا از نوع Dynamic باشند ولی در عوض چهار طرف صفحه را می بندیم تا کسی فرار نکند ;-)

برای درک کد بعدی باید مطالب قبلی را به خوبی مطالعه کرده باشید.


package com.safecomp.andenginetutone;

import java.io.IOException;

import org.andengine.engine.Engine;
import org.andengine.engine.FixedStepEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;
import org.andengine.ui.activity.BaseGameActivity;

import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;

public class RevoluteJointExample extends BaseGameActivity implements
		IAccelerationListener {
	private Camera pCamera;
	Scene pScene;
	private static final int CAMERA_WIDTH = 720;
	private static final int CAMERA_HEIGHT = 480;

	Rectangle rectA;
	Rectangle rectB;
	Rectangle rectC;

	Body bodyA;
	Body bodyB;
	Body bodyC;

	FixtureDef fixture;

	FixtureDef WALL_FIXTURE_DEF;

	Body groundWallBody;
	Rectangle ground;
	Body roofWallBody;
	Rectangle roof;
	Body leftWallBody;
	Rectangle left;
	Body rightWallBody;
	Rectangle right;

	PhysicsWorld pPhysicsWorld;

	RevoluteJointDef revoluteJointDef;
	RevoluteJointDef revoluteJointDef2;

	@Override
	public Engine onCreateEngine(EngineOptions pEngineOptions) {
		return new FixedStepEngine(pEngineOptions, 60);
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		pCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions eo = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
						CAMERA_WIDTH, CAMERA_HEIGHT), pCamera);
		return eo;
	}

	@Override
	public void onCreateResources(
			OnCreateResourcesCallback pOnCreateResourcesCallback)
			throws IOException {
		pOnCreateResourcesCallback.onCreateResourcesFinished();
	}

	@Override
	public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
			throws IOException {
		pScene = new Scene();
		pScene.setBackground(new Background(0, .7f, .7f));

		pPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0f,
				-SensorManager.GRAVITY_EARTH * 2), false, 8, 3);

		fixture = PhysicsFactory.createFixtureDef(20, .2f, .9f);

		WALL_FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.1f, 0.5f);

		ground = new Rectangle(CAMERA_WIDTH / 2f, 6f, CAMERA_WIDTH - 4f, 8f,
				getVertexBufferObjectManager());
		roof = new Rectangle(CAMERA_WIDTH / 2f, CAMERA_HEIGHT - 6f,
				CAMERA_WIDTH - 4f, 8f, getVertexBufferObjectManager());
		left = new Rectangle(6f, CAMERA_HEIGHT / 2f, 8f, CAMERA_HEIGHT - 4f,
				getVertexBufferObjectManager());
		right = new Rectangle(CAMERA_WIDTH - 6f, CAMERA_HEIGHT / 2f, 8f,
				CAMERA_HEIGHT - 4f, getVertexBufferObjectManager());

		ground.setColor(0, 0, 0);
		roof.setColor(0, 0, 0);
		left.setColor(0, 0, 0);
		right.setColor(0, 0, 0);

		groundWallBody = PhysicsFactory.createBoxBody(pPhysicsWorld, ground,
				BodyType.StaticBody, WALL_FIXTURE_DEF);
		roofWallBody = PhysicsFactory.createBoxBody(pPhysicsWorld, roof,
				BodyType.StaticBody, WALL_FIXTURE_DEF);
		leftWallBody = PhysicsFactory.createBoxBody(pPhysicsWorld, left,
				BodyType.StaticBody, WALL_FIXTURE_DEF);
		rightWallBody = PhysicsFactory.createBoxBody(pPhysicsWorld, right,
				BodyType.StaticBody, WALL_FIXTURE_DEF);

		pScene.attachChild(ground);
		pScene.attachChild(roof);
		pScene.attachChild(left);
		pScene.attachChild(right);

		rectA = new Rectangle(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, 200, 40,
				getVertexBufferObjectManager());
		rectA.setColor(1, 0, 0);

		pScene.attachChild(rectA);

		bodyA = PhysicsFactory.createBoxBody(pPhysicsWorld, rectA,
				BodyType.DynamicBody, fixture);
		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectA,
				bodyA));

		rectB = new Rectangle(CAMERA_WIDTH / 2 + 100, CAMERA_HEIGHT / 2, 100,
				40, getVertexBufferObjectManager());
		rectB.setColor(0, 1, 0);

		pScene.attachChild(rectB);

		bodyB = PhysicsFactory.createBoxBody(pPhysicsWorld, rectB,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectB,
				bodyB));

		rectC = new Rectangle(CAMERA_WIDTH / 2 - 100, CAMERA_HEIGHT / 2, 100,
				40, getVertexBufferObjectManager());
		rectC.setColor(0, 0, 1);

		pScene.attachChild(rectC);

		bodyC = PhysicsFactory.createBoxBody(pPhysicsWorld, rectC,
				BodyType.DynamicBody, fixture);

		pPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectC,
				bodyC));

		// revolute joint bodyA and bodyB
		revoluteJointDef = new RevoluteJointDef();

		revoluteJointDef.initialize(bodyA, bodyB, bodyA.getWorldCenter());

		float xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorA.set(xa, 0);

		float xb = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef.localAnchorB.set(xb, 0);

		revoluteJointDef.enableMotor = true;
		revoluteJointDef.motorSpeed = -1;
		revoluteJointDef.maxMotorTorque = 5000;

		RevoluteJoint rj = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef);

		// revolute joint bodyA and bodyC
		revoluteJointDef2 = new RevoluteJointDef();

		revoluteJointDef2.initialize(bodyA, bodyC, bodyA.getWorldCenter());

		xa = 100f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef2.localAnchorA.set(-xa, 0);

		float xc = 50f / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT;
		revoluteJointDef2.localAnchorB.set(xc, 0);

		revoluteJointDef2.enableMotor = true;
		revoluteJointDef2.motorSpeed = 1;
		revoluteJointDef2.maxMotorTorque = 5000;

		RevoluteJoint rj2 = (RevoluteJoint) pPhysicsWorld
				.createJoint(revoluteJointDef2);

		pScene.registerUpdateHandler(pPhysicsWorld);
		pOnCreateSceneCallback.onCreateSceneFinished(pScene);
	}

	@Override
	public void onPopulateScene(Scene pScene,
			OnPopulateSceneCallback pOnPopulateSceneCallback)
			throws IOException {
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

	@Override
	public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) {
	}

	@Override
	public void onAccelerationChanged(AccelerationData pAccelerationData) {

		Vector2 gravity = Vector2Pool.obtain(pAccelerationData.getX(),
				pAccelerationData.getY());
		pPhysicsWorld.setGravity(gravity);
		Vector2Pool.recycle(gravity);
	}

	@Override
	public synchronized void onResumeGame() {
		enableAccelerationSensor(this);
		super.onResumeGame();
	}

	@Override
	public synchronized void onPauseGame() {
		disableAccelerationSensor();
		super.onPauseGame();
	}

}

خروجی :

حد :

مثال هایی که تا اینجا مشاهده کردیم در محور چرخش هیچ محدودیتی نداشتند ولی همانطور که قبلاً گفتم revolute joint این ویژگی را دارد که چرخش آن را بین دو زاویه خاص محدود کنیم ، دقت کنید که اندانجین از رادیان استفاده می کند و باید تعریف زوایا به درجه را به رادیان تبدیل کنید.

خطوط زیر نحوه فعال کرد حد را نمایش میدهد :


	revoluteJointDef.enableLimit=true;
	revoluteJointDef.lowerAngle=(float)Math.toRadians(20);
	revoluteJointDef.upperAngle=(float)Math.toRadians(90);


 

Plain text

  • تگ‌های HTML مجاز نیستند.
  • نشانی صفحه‌ها وب و پست الکترونیک بصورت خودکار به پیوند تبدیل می‌شوند.
  • خطوط و پاراگراف‌ها بطور خودکار اعمال می‌شوند.