andengine中使用box2D后对entity进行初始速度设定

在AndEngine框架中,实现StupidZombie游戏过程中遇到如何随意控制小球初始移动速度的问题,并通过设置速度来使小球移动。文章详细介绍了通过派生AnimatedSprite类并设置速度的方法,最终实现小球按指定速度移动的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在学习andengine的过程中,模仿实现StupidZombie的游戏实现,andengine中嵌入box2D的PhysicsWorld,方便碰撞检测、自动物体碰撞后的自动反射移动,但碰到个问题,看andengine的box2d相关的例子,不知道发现实现随意控制小球的初始移动速度(即根据发射原理根据手触屏距离某个点的位置设置小球的x、y方向的移动速度)(其实andengineExample中有该代码的控制,但刚开始没有找到)

试了多种方法,如:自己派生AnimatedSprite,实现控制x、y的控制,但有问题,只在原地附近闪烁,而没有移动,如下代码:

	//球:用于设置速度和加速度
	class CircleAnimateSprite extends AnimatedSprite{
		PhysicsHandler	m_handlerPhysics;
		
		public CircleAnimateSprite(float pX, float pY, ITiledTextureRegion pTiledTextureRegion, VertexBufferObjectManager pVertexBufferObjectManager) {
			super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager);
			// TODO Auto-generated constructor stub
			m_handlerPhysics = new PhysicsHandler(this);
			registerUpdateHandler(m_handlerPhysics);
			m_handlerPhysics.setVelocity(0, 0);
		}

		@Override
		protected void onManagedUpdate(float pSecondsElapsed) {
			// TODO Auto-generated method stub			
//			if (mX <= 2)	//屏不屏蔽代码都一样在附近闪烁
//				m_handlerPhysics.setVelocityX(m_handlerPhysics.getVelocityX());
//			else if (mX + getWidth() >= N_Camera_Width - 2)
//				m_handlerPhysics.setVelocityX(-m_handlerPhysics.getVelocityX());
//			
//			if (mY <= 2)
//				m_handlerPhysics.setVelocityY(m_handlerPhysics.getVelocityY());
//			else if (mY + getHeight() >= N_Camera_Height - 2)
//				m_handlerPhysics.setVelocityY(-m_handlerPhysics.getVelocityY());
//			
//			mX += pSecondsElapsed * m_handlerPhysics.getVelocityX();
//			mY += pSecondsElapsed * m_handlerPhysics.getVelocityY();
//			setPosition(mX, mY);
//			m_handlerPhysics.setVelocity(m_fVelocityX, m_fVelocityY);

			super.onManagedUpdate(pSecondsElapsed);
		}
		
		public void setVelocity(float fx, float fy){
			if (m_handlerPhysics != null){
				m_handlerPhysics.setVelocity(fx, fy);	//看了半天,也没发现该handler的用法,设置了也没产生速度的作用,只是闪烁
//				m_handlerPhysics.setAcceleration(fx, fy);
//				m_handlerPhysics.setAngularVelocity(0.8f);
			}
		}
	}
当然,估计上面的闪烁是因为和PhysicsWorld产生了冲突:m_physicsWorld.registerPhysicsConnector(new PhysicsConnector(m_asCircle, bodyCircle));

Google查找,可惜google被屏蔽了,悲催的无语,最后搜到一篇文章:AndEngine学习笔记10-Physics中关于PhysicsMouseJointExample 的介绍,才知道andengineExample中有了随意设定速度的代码(andengine没有文档啊没有文档,悲剧的无语,而且搞的实例中连注释都没有,哎,这习惯。。)

andengine中的关于设置速度的代码如下:

private void jumpFace(final AnimatedSprite face) {
	final Body faceBody = (Body)face.getUserData();	//此处的getUserData是自己通过setUserData设置的,也可以通过传值、成员变量实现

	final Vector2 velocity = Vector2Pool.obtain(this.mGravityX * -50, this.mGravityY * -50);
	faceBody.setLinearVelocity(velocity);
	Vector2Pool.recycle(velocity);
}
其实这里边关键的一句话就是body.setLinearVelocity,即也可以body.setLinearVelocity(fx, fy);

将自己刚开始做的代码附上,方便自己,也方便想交流的朋友,andengine啊,没有文档、注释,太他妈的无语了
package com.nocom.stupidzombie;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.handler.physics.PhysicsHandler;
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.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.scene.menu.MenuScene;
import org.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.andengine.entity.scene.menu.item.IMenuItem;
import org.andengine.entity.scene.menu.item.TextMenuItem;
import org.andengine.entity.scene.menu.item.decorator.ColorMenuItemDecorator;
import org.andengine.entity.shape.IShape;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.util.FPSLogger;
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.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.color.Color;
import org.andengine.util.math.MathUtils;

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 android.hardware.SensorManager;
import android.view.KeyEvent;


public class StupidZombieActivity extends SimpleBaseGameActivity implements IOnMenuItemClickListener, IOnSceneTouchListener{

	public static final int		N_Camera_Width = 800;
	public static final int		N_Camera_Height = 480;
	private static final int	N_MenuItem_Resume = 0;
	private static final int	N_MenuItem_Reset = 1;
	private static final int	N_MenuItem_Quit = 2;
	private static final String	S_MenuItem_Resume = "Resume";
	private static final String	S_MenuItem_Reset = "Reset";
	private static final String	S_MenuItem_Quit = "Quit";
	private Camera				m_camera;
	private Scene				m_sceneMain;
	private MenuScene			m_sceneMenu;
	private Font				m_fontMenu;
	private SpriteBackground	m_bgMain;
	private TiledTextureRegion	m_ttrCircle;
	private TextureRegion		m_trZombie;
	private PhysicsWorld		m_world;
	private	FixtureDef			m_fdWall;
	private AnimatedSprite		m_asCircle;
	
	
	@Override
	public EngineOptions onCreateEngineOptions() {
		// TODO Auto-generated method stub
		m_camera = new Camera(0, 0, N_Camera_Width, N_Camera_Height);
		EngineOptions	eo = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(N_Camera_Width, N_Camera_Height), m_camera);
		return eo;
	}

	@Override
	protected void onCreateResources() {
		// TODO Auto-generated method stub
		//设置menu的字体
		FontFactory.setAssetBasePath("font/");
		final ITexture	textureFont = new BitmapTextureAtlas(getTextureManager(), 256, 256, TextureOptions.BILINEAR);
		m_fontMenu = FontFactory.createFromAsset(getFontManager(), textureFont, getAssets(), "Plok.ttf", 48, true, android.graphics.Color.WHITE);
		m_fontMenu.load();
		
		//创建内存空间及加载背景
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		final BitmapTextureAtlas	bta = new BitmapTextureAtlas(getTextureManager(), 1024, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		TextureRegion				trBG = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, this, "background.png", 0, 0);
		m_bgMain = new SpriteBackground(new Sprite(0, 0, trBG, getVertexBufferObjectManager()));
		//加载实体
		m_ttrCircle = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(bta, this, "circle.png", 800, 0, 2, 1);
		m_trZombie = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, this, "zombie.png", 864, 0);
		bta.load();
	}

	@Override
	protected Scene onCreateScene() {
		// TODO Auto-generated method stub
		mEngine.registerUpdateHandler(new FPSLogger());

		//
		m_sceneMain = new Scene();
		m_sceneMain.setBackground(m_bgMain);
		m_sceneMain.setOnSceneTouchListener(this);
		m_sceneMain.registerUpdateHandler(new CollisionDetectionUpdateHandler());
		
		//创建暂停时的menu
		createMenuScene();
		//创建世界模型
		createPhysicsWorld(m_sceneMain);
		//创建世界中的实体
		createPhysicsWorldEntity(m_sceneMain);
		//..temp
		addCircleEntity(m_sceneMain, 100, N_Camera_Height - 100);
		
		return m_sceneMain;
	}

	@Override
	public boolean onMenuItemClicked(MenuScene arg0, IMenuItem arg1, float arg2, float arg3) {
		// TODO Auto-generated method stub
		switch (arg1.getID()){
			case N_MenuItem_Resume:
				if (m_sceneMain.hasChildScene())
					m_sceneMenu.back();
				break;
			case N_MenuItem_Reset:
				m_sceneMain.reset();
				m_sceneMain.clearChildScene();
				
				m_sceneMenu.reset();
				return true;
			case N_MenuItem_Quit:
				finish();
				return true;
		}
		return false;
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) && event.getAction() == KeyEvent.ACTION_DOWN){
			if (m_sceneMenu != null){
				if (m_sceneMain.hasChildScene())
					m_sceneMenu.back();
				else
					m_sceneMain.setChildScene(m_sceneMenu, false, true, true);
				return true;
			}
		}
		
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onSceneTouchEvent(Scene arg0, TouchEvent arg1) {
		// TODO Auto-generated method stub
		if (m_asCircle != null){
			shoot(m_asCircle, arg1.getX(), arg1.getY());
		}
		
		return false;
	}
	
	//创建暂停时的menu
	void createMenuScene(){
		m_sceneMenu = new MenuScene(m_camera);
		
		IMenuItem	itemResume = new ColorMenuItemDecorator(new TextMenuItem(N_MenuItem_Resume, m_fontMenu, S_MenuItem_Resume, getVertexBufferObjectManager()), new Color(0.8f, 0.3f, 0), new Color(0, 0.3f, 0.8f));
		m_sceneMenu.addMenuItem(itemResume);
		
		IMenuItem	itemReset = new ColorMenuItemDecorator(new TextMenuItem(N_MenuItem_Reset, m_fontMenu, S_MenuItem_Reset, getVertexBufferObjectManager()), new Color(0.8f, 0.3f, 0), new Color(0, 0.3f, 0.8f));
		m_sceneMenu.addMenuItem(itemReset);
		
		IMenuItem	itemQuit = new ColorMenuItemDecorator(new TextMenuItem(N_MenuItem_Quit, m_fontMenu, S_MenuItem_Quit, getVertexBufferObjectManager()), new Color(0.8f, 0.3f, 0), new Color(0, 0.3f, 0.8f));
		m_sceneMenu.addMenuItem(itemQuit);
		
		m_sceneMenu.buildAnimations();
		m_sceneMenu.setBackgroundEnabled(false);
		m_sceneMenu.setOnMenuItemClickListener(this);
	}
	
	//创建世界模型
	void createPhysicsWorld(Scene scene){
		m_world = new PhysicsWorld(new Vector2(0, 0), false);	//SensorManager.GRAVITY_PLUTO
		Rectangle	top = new Rectangle(0, 0, N_Camera_Width, 2, getVertexBufferObjectManager());
		Rectangle	bottom = new Rectangle(0, N_Camera_Height - 2, N_Camera_Width, 2, getVertexBufferObjectManager());
		Rectangle	left = new Rectangle(0, 0, 2, N_Camera_Height, getVertexBufferObjectManager());
		Rectangle	right = new Rectangle(N_Camera_Width - 2, 0, 2, N_Camera_Height, getVertexBufferObjectManager());
		//设置墙的密度、弹性、摩擦力
		m_fdWall = PhysicsFactory.createFixtureDef(0, 0.8f, 0.3f);
		PhysicsFactory.createBoxBody(m_world, top, BodyType.StaticBody, m_fdWall);
		PhysicsFactory.createBoxBody(m_world, bottom, BodyType.StaticBody, m_fdWall);
		PhysicsFactory.createBoxBody(m_world, left, BodyType.StaticBody, m_fdWall);
		PhysicsFactory.createBoxBody(m_world, right, BodyType.StaticBody, m_fdWall);
		
		//添加到场景中
		scene.attachChild(top);
		scene.attachChild(bottom);
		scene.attachChild(left);
		scene.attachChild(right);
		scene.registerUpdateHandler(m_world);
	}

	//创建世界中的实体
	void createPhysicsWorldEntity(Scene scene){
		//关卡1(此处为测试用,待多个时再单独拉出划分模块)
		{
			//添加世界中的zombie站立的地板
			Rectangle	rect1 = new Rectangle(30, N_Camera_Height / 3 - 20, N_Camera_Width / 10, 10, getVertexBufferObjectManager());
			Rectangle	rect2 = new Rectangle(50, N_Camera_Height / 3 * 2 - 10, N_Camera_Width / 8, 12, getVertexBufferObjectManager());
			Rectangle	rect3 = new Rectangle(N_Camera_Width - N_Camera_Width / 8, N_Camera_Height / 3 + 10, N_Camera_Width / 7, 15, getVertexBufferObjectManager());
			Rectangle	rect4 = new Rectangle(N_Camera_Width - N_Camera_Width / 14, N_Camera_Height / 3 * 2 + 20, N_Camera_Width / 15, 20, getVertexBufferObjectManager());
			rect1.setColor(0, 0, 0);
			rect2.setColor(0, 0, 0);
			rect3.setColor(0, 0, 0);
			rect4.setColor(0, 0, 0);
			PhysicsFactory.createBoxBody(m_world, rect1, BodyType.StaticBody, m_fdWall);
			PhysicsFactory.createBoxBody(m_world, rect2, BodyType.StaticBody, m_fdWall);
			PhysicsFactory.createBoxBody(m_world, rect3, BodyType.StaticBody, m_fdWall);
			PhysicsFactory.createBoxBody(m_world, rect4, BodyType.StaticBody, m_fdWall);
			scene.attachChild(rect1);
			scene.attachChild(rect2);
			scene.attachChild(rect3);
			scene.attachChild(rect4);

			//添加世界中的zombie
			FixtureDef		fdZombie = PhysicsFactory.createFixtureDef(0.1f, 0, 0.1f);
			Sprite		spritZombie1 = new Sprite(rect1.getX(), rect1.getY() - m_trZombie.getHeight(), m_trZombie, getVertexBufferObjectManager());
			Sprite		spritZombie2 = new Sprite(rect2.getX(), rect2.getY() - m_trZombie.getHeight(), m_trZombie, getVertexBufferObjectManager());
			Sprite		spritZombie3 = new Sprite(rect3.getX(), rect3.getY() - m_trZombie.getHeight(), m_trZombie, getVertexBufferObjectManager());
			Sprite		spritZombie4 = new Sprite(rect4.getX(), rect4.getY() - m_trZombie.getHeight(), m_trZombie, getVertexBufferObjectManager());
			PhysicsFactory.createBoxBody(m_world, spritZombie1, BodyType.DynamicBody, fdZombie);
			PhysicsFactory.createBoxBody(m_world, spritZombie2, BodyType.DynamicBody, fdZombie);
			PhysicsFactory.createBoxBody(m_world, spritZombie3, BodyType.DynamicBody, fdZombie);
			PhysicsFactory.createBoxBody(m_world, spritZombie4, BodyType.DynamicBody, fdZombie);
			scene.attachChild(spritZombie1);
			scene.attachChild(spritZombie2);
			scene.attachChild(spritZombie3);
			scene.attachChild(spritZombie4);
		}
	}
	
	//添加小球
	void addCircleEntity(Scene scene, float fx, float fy){
		//添加世界中的球
		if (m_asCircle == null){
			FixtureDef		fdCircle = PhysicsFactory.createFixtureDef(100, 0, 0);
			m_asCircle = new AnimatedSprite(fx, fy, m_ttrCircle, getVertexBufferObjectManager());
			Body			bodyCircle = PhysicsFactory.createCircleBody(m_world, m_asCircle, BodyType.DynamicBody, fdCircle);
			m_asCircle.animate(150);
			m_asCircle.setUserData(bodyCircle);
			scene.attachChild(m_asCircle);
			m_world.registerPhysicsConnector(new PhysicsConnector(m_asCircle, bodyCircle));
		}
//		else{
//			m_asCircle.setPosition(fx, fy);
//		}
	}
	
	//发射小球
	void shoot(AnimatedSprite as, float fx, float fy){
		Body	body = (Body)as.getUserData();
//		Vector2	vec2 = Vector2Pool.obtain(fx, fy);
//		body.setLinearVelocity(vec2);
//		Vector2Pool.recycle(vec2);
		
		body.setLinearVelocity(fx, fy);		//改变Sprite速度关键的是Body.setLinearVelocity函数
	}

	
	//用于设置子弹的位置、碰撞检测的处理等
	class CollisionDetectionUpdateHandler implements IUpdateHandler{

		@Override
		public void onUpdate(float arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void reset() {
			// TODO Auto-generated method stub
			
		}
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值