gpt4 book ai didi

java - 如何将对象从节点移动到节点? Libgdx Box2d A*寻路

转载 作者:行者123 更新时间:2023-12-01 11:17:46 32 4
gpt4 key购买 nike

我无法成功地让敌人从一个节点移动到另一个节点。
我设法设置了整个寻路,我得到了玩家的完整路径和下一个节点的位置,一直到最后。
如何将 box2d 主体从一个节点移动到另一个节点?
或者更简单 - 如何将 box2d 主体移动到某个位置?
我尝试施加冲动,力量无法做到。
这是我的简化代码。 Monster 和 Player 类都扩展了 Sprite:

public class B2dSteeringEntity implements Steerable<Vector2>, Updateable {

public static final String TAG = B2dSteeringEntity.class.getName();

Body body;
boolean tagged;
float maxLinearSpeed, maxLinearAcceleration;
float maxAngularSpeed, maxAngularAcceleration;
float boundingRadius;

SteeringBehavior<Vector2> behavior;
SteeringAcceleration<Vector2> steeringOutput;

public B2dSteeringEntity(Body body, float boundingRadius) {
this.body = body;
this.boundingRadius = boundingRadius;

this.maxLinearSpeed = 250;
this.maxLinearAcceleration = 200;
this.maxAngularSpeed = 0;
this.maxAngularAcceleration = 0;

this.tagged = false;

this.steeringOutput = new SteeringAcceleration<Vector2>(new Vector2());
}

@Override
public Vector2 getLinearVelocity() {
return body.getLinearVelocity();
}

@Override
public float getAngularVelocity() {
return body.getAngularVelocity();
}

@Override
public float getBoundingRadius() {
return 0;
}

@Override
public boolean isTagged() {
return tagged;
}

@Override
public void setTagged(boolean tagged) {
this.tagged = tagged;
}

@Override
public float getZeroLinearSpeedThreshold() {
return 0;
}

@Override
public void setZeroLinearSpeedThreshold(float value) {

}

@Override
public float getMaxLinearSpeed() {
return maxLinearSpeed;
}

@Override
public void setMaxLinearSpeed(float maxLinearSpeed) {
this.maxLinearSpeed = maxLinearSpeed;
}

@Override
public float getMaxLinearAcceleration() {
return maxLinearAcceleration;
}

@Override
public void setMaxLinearAcceleration(float maxLinearAcceleration) {
this.maxLinearAcceleration = maxLinearAcceleration;
}

@Override
public float getMaxAngularSpeed() {
return maxAngularSpeed;
}

@Override
public void setMaxAngularSpeed(float maxAngularSpeed) {
this.maxAngularSpeed = maxAngularSpeed;
}

@Override
public float getMaxAngularAcceleration() {
return maxAngularAcceleration;
}

@Override
public void setMaxAngularAcceleration(float maxAngularAcceleration) {
this.maxAngularAcceleration = maxAngularAcceleration;
}

@Override
public Vector2 getPosition() {
return body.getPosition();
}

@Override
public float getOrientation() {
return body.getAngle();
}

@Override
public void setOrientation(float orientation) {

}

@Override
public float vectorToAngle(Vector2 vector) {
return SteeringUtils.vectorToAngle(vector);
}

@Override
public Vector2 angleToVector(Vector2 outVector, float angle) {
return SteeringUtils.angleToVector(outVector, angle);
}

@Override
public Location<Vector2> newLocation() {
return null;
}

public Body getBody() {
return body;
}

public void setBehavior(SteeringBehavior<Vector2> behavior) {
this.behavior = behavior;
}

public SteeringBehavior<Vector2> getBehavior() {
return behavior;
}

private void applySteering(float deltaTime) {
boolean anyAccelerations = false;

if(!steeringOutput.linear.isZero()) {
Vector2 force = steeringOutput.linear.scl(deltaTime);
body.applyForceToCenter(force, true);
anyAccelerations = true;
}

if(anyAccelerations) {
Vector2 velocity = body.getLinearVelocity();
float currentSpeedSquare = velocity.len2();
if(currentSpeedSquare > maxLinearSpeed * maxLinearSpeed) {
body.setLinearVelocity(velocity.scl(maxLinearSpeed / (float) Math.sqrt(currentSpeedSquare)));
}

if (body.getAngularVelocity() > maxAngularSpeed) {
body.setAngularVelocity(maxAngularSpeed);
}
}
}

@Override
public void update(float deltaTime) {
if (behavior != null) {
behavior.calculateSteering(steeringOutput);
applySteering(deltaTime);
}
}
}
public Skeleton(B2WorldCreator creator, GameScreen screen, float x, float y, State state, HeroKnight player) {
super(creator, screen, x, y, state, player);
controller = screen.getController();
setBounds(x, y, 150 / Constants.PPM, 150 / Constants.PPM);
enemyAgentComponent = new EnemyAgentComponent(b2body, b2dSteeringEntity, controller, player);

}
这是 EnemyAgentComponent 类:
public class EnemyAgentComponent implements Component, Telegraph, Updateable, Pather<Node> {

public static final String TAG = EnemyAgentComponent.class.getName();
public StateMachine<EnemyAgentComponent, EnemyState> stateMachine;

public boolean isInProximity() {
return inProximity;
}

public boolean inProximity = false;
public boolean lowHP = false;
public boolean isShot = false;
private boolean isRequested = false;
private boolean requestingMovement;

private Steering wayPoint;
private Body body;
private Controller controller;

private HeroKnight player;
private Node startNode, endNode, previousStartNode, previousEndNode;
private Vector2 goal;
private PathfindingTarget newGoal;
private float impulseMag;

private boolean nodeReached;
private boolean pathGenerated;
private Arrive<Vector2> arriveSB;
private Steering waypoint;
private B2dSteeringEntity steering;
private IndexedAStarPathFinder<Node> pathFinder;
private GraphPathImp resultPath = new GraphPathImp();
private float pathfindingTimer;
private boolean firstPathGenerated;

public boolean isTouchingPlayer() {
return touchingPlayer;
}

public void setTouchingPlayer(boolean touchingPlayer) {
this.touchingPlayer = touchingPlayer;
}

private boolean touchingPlayer;

public EnemyAgentComponent(Body body, B2dSteeringEntity steering, Controller controller, HeroKnight player) {
construct(body, steering, controller, player);
}

public void construct(Body body, B2dSteeringEntity steering, Controller controller, HeroKnight player) {
this.steering = steering;
this.controller = controller;
this.body = body;
this.player = player;
stateMachine = new DefaultStateMachine<>(this, EnemyState.SEEKING);
MessageManager.getInstance().addListener(this, Messages.PLAYER_IN_SIGHT);
MessageManager.getInstance().addListener(this, Messages.PLAYER_ATTACKED_ENEMY);
MessageManager.getInstance().addListener(this, Messages.LOW_HP);
MessageManager.getInstance().addListener(this, Messages.PLAYER_OUT_OF_SIGHT);
MessageManager.getInstance().addListener(this, Messages.TOUCHING_PLAYER);

pathFinder = new IndexedAStarPathFinder<Node>(LevelManager.groundGraph, false);
requestingMovement = false;
goal = null;
nodeReached = false;
pathGenerated = false;
firstPathGenerated = false;
pathfindingTimer = 0;
touchingPlayer = false;
}
public Vector2 getGoal() {
return goal;
}

public boolean isRequestingMovement() {
return requestingMovement;
}

public void setRequestingMovement(boolean requestingMovement) {
this.requestingMovement = requestingMovement;
}

public boolean isPathGenerated() {
return pathGenerated;
}

public GraphPathImp getResultPath() {
return resultPath;
}

public void generatePath() {
previousEndNode = endNode;
previousStartNode = startNode;
resultPath.clear();
pathFinder.searchNodePath(startNode, endNode, new HeuristicImp(), resultPath);
newGoal = new PathfindingTarget(resultPath.get(0).getNodePosition());
pathGenerated = true;
}

public void update(float deltaTime) {
startNode = LevelManager.groundGraph.getNodeByXY(body.getPosition().x, body.getPosition().y);
endNode = LevelManager.groundGraph.getNodeByXY(player.b2body.getPosition().x, player.b2body.getPosition().y);
//If player gets in certain range of the enemy and is not touching the enemy, enemy's path is being generated
if (inProximity) {
if (!firstPathGenerated && !touchingPlayer)
if ((pathfindingTimer == 0)) {
generatePath();
previousStartNode = startNode;
previousEndNode = endNode;
firstPathGenerated = true;
}

//If a path was already created, a new path is being requested only if player's position changes
if (firstPathGenerated && (previousEndNode != endNode) && pathfindingTimer == 0 && !touchingPlayer) {
generatePath();
}
if (firstPathGenerated)
pathfindingTimer += deltaTime;
//Paths are generated every 2 seconds
if (pathfindingTimer >= 2) {
pathfindingTimer = 0;
}
//If enemy touches the player pathfinding ends
if (touchingPlayer) {
pathfindingTimer = 0;
pathGenerated = false;
resultPath.clear();
body.setLinearVelocity(0, 0);
}
}
//The arrive behaviour is set, newGoal being the position of next node
if (steering.getLinearVelocity().x == 0 && steering.getLinearVelocity().y == 0 && newGoal != null) {
steering.setBehavior(new Arrive<Vector2>(steering, newGoal));
}

steering.update(deltaTime);
//Updating the next node position based on the enemy reaching a node
if (pathGenerated)
if (Math.abs(body.getPosition().x - newGoal.getPosition().x) <= 0.1f && Math.abs(body.getPosition().y - newGoal.getPosition().y) <= 51 / 2f / Constants.PPM)
{
updatePath();
}
}


public void updatePath() {
//Setting the next target position
if (resultPath.getCount() > 0) {
resultPath.removeIndex(0);
if (!touchingPlayer && resultPath.getCount() > 0) {
newGoal.setPosition(resultPath.get(0).getNodePosition());
requestingMovement = true;
nodeReached = false;
}
}
}


@Override
public boolean handleMessage(Telegram telegram) {
if (telegram.message == Messages.PLAYER_IN_SIGHT) {
inProximity = true;

return true;
}
if (telegram.message == Messages.PLAYER_OUT_OF_SIGHT) {
inProximity = false;
firstPathGenerated = false;
pathGenerated = false;
pathfindingTimer = 0;
resultPath.clear();
}
if (telegram.message == Messages.LOW_HP) {
lowHP = true;

return true;
}
if (telegram.message == Messages.PLAYER_ATTACKED_ENEMY) {
isShot = true;

return true;
}
if (telegram.message == Messages.TOUCHING_PLAYER) {
touchingPlayer = true;
return true;
}

return false;
}


@Override
public void acceptPath(PathFinderRequest<Node> request) {
if (request.pathFound) {
resultPath = (GraphPathImp) request.resultPath;
}
}
}
正在使用 skeleton.update(deltaTime) 和 skeleton.draw(deltaTime) 更新和绘制骨架类。
编辑2:
现在尝试使用线性脉冲,运动很笨重:
if (newGoal != null) {
Vector2 direction = new Vector2(newGoal.getPosition().x - body.getPosition().x, newGoal.getPosition().y - body.getPosition().y).nor();
float speed = Constants.SKELETON_SPEED;
Vector2 velocity = new Vector2(speed * direction.x, speed * direction.y);
body.applyLinearImpulse(velocity.x * body.getMass(), velocity.y * body.getMass(), body.getWorldCenter().x, body.getWorldCenter().y, true);
}
if (pathGenerated)
if (Math.abs(body.getPosition().x - newGoal.getPosition().x) <= 0.1f && Math.abs(body.getPosition().y - newGoal.getPosition().y) <= 51 / 2f / Constants.PPM)
{
Gdx.app.debug(TAG, "Node reached!");
updatePath();
}

最佳答案

移动实体与 AI 没有直接关系。 AI 只是找到了一条路,实体跟随它。
使用 box2d,你必须向正确的方向施加力或脉冲,确保你的 box2d 世界的 step() 方法被调用并更新你的实体渲染坐标(例如 Sprite )以匹配 box2d 的 body 坐标。然后在下一个循环中再次从新坐标调用您的 AI,确定您现在必须向哪个方向移动并再次施加您的力。
所以循环看起来像

  • AI找路
  • 从您的位置查找到下一个节点的方向
  • 施加力/脉冲
  • box2d 世界步
  • 调整实体渲染坐标以匹配 box2d 主体位置
  • 重复

  • 为您提供更详细的答案需要更多有关如何渲染实体以及循环外观的知识。请分享一些 example code .
    编辑:添加一些代码后,我发现仍然不清楚您的实际问题是什么。您可以移动您的实体但无法阻止它吗?它会移动吗?你打电话吗 world.step() ?快速浏览后我能发现的唯一明显问题是您使用 deltaTime 缩放 applyForceToCenter ,这不是必需的,因为 world.step 已经将 timeStep 作为参数。

    关于java - 如何将对象从节点移动到节点? Libgdx Box2d A*寻路,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62696067/

    32 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com