/******************************************************************************* * Copyright 2014 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.ai.tests.steer.box2d.tests; import com.badlogic.gdx.ai.GdxAI; import com.badlogic.gdx.ai.steer.Steerable; import com.badlogic.gdx.ai.steer.behaviors.CollisionAvoidance; import com.badlogic.gdx.ai.steer.behaviors.PrioritySteering; import com.badlogic.gdx.ai.steer.behaviors.Wander; import com.badlogic.gdx.ai.steer.limiters.LinearAccelerationLimiter; import com.badlogic.gdx.ai.tests.SteeringBehaviorsTest; import com.badlogic.gdx.ai.tests.steer.box2d.Box2dRadiusProximity; import com.badlogic.gdx.ai.tests.steer.box2d.Box2dSteeringEntity; import com.badlogic.gdx.ai.tests.steer.box2d.Box2dSteeringTest; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.Slider; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Array; /** A class to test and experiment with the {@link CollisionAvoidance} behavior. * * @autor davebaol */ public class Box2dCollisionAvoidanceTest extends Box2dSteeringTest { Array<Box2dSteeringEntity> characters; Box2dRadiusProximity char0Proximity; Array<Box2dRadiusProximity> proximities; boolean drawDebug; ShapeRenderer shapeRenderer; private Batch spriteBatch; public Box2dCollisionAvoidanceTest (SteeringBehaviorsTest container) { super(container, "Collision Avoidance"); } @Override public void create () { super.create(); drawDebug = true; shapeRenderer = new ShapeRenderer(); spriteBatch = new SpriteBatch(); characters = new Array<Box2dSteeringEntity>(); proximities = new Array<Box2dRadiusProximity>(); for (int i = 0; i < 60; i++) { final Box2dSteeringEntity character = createSteeringEntity(world, container.greenFish, false); character.setMaxLinearSpeed(2); character.setMaxLinearAcceleration(4); Box2dRadiusProximity proximity = new Box2dRadiusProximity(character, world, character.getBoundingRadius() * 4); proximities.add(proximity); if (i == 0) char0Proximity = proximity; CollisionAvoidance<Vector2> collisionAvoidanceSB = new CollisionAvoidance<Vector2>(character, proximity); Wander<Vector2> wanderSB = new Wander<Vector2>(character) // // Don't use Face internally because independent facing is off .setFaceEnabled(false) // // We don't need a limiter supporting angular components because Face is not used // No need to call setAlignTolerance, setDecelerationRadius and setTimeToTarget for the same reason .setLimiter(new LinearAccelerationLimiter(5)) // .setWanderOffset(3) // .setWanderOrientation(5) // .setWanderRadius(1) // .setWanderRate(MathUtils.PI2 * 4); PrioritySteering<Vector2> prioritySteeringSB = new PrioritySteering<Vector2>(character, 0.0001f); prioritySteeringSB.add(collisionAvoidanceSB); prioritySteeringSB.add(wanderSB); character.setSteeringBehavior(prioritySteeringSB); setRandomNonOverlappingPosition(character, characters, Box2dSteeringTest.pixelsToMeters(5)); characters.add(character); } inputProcessor = null; Table detailTable = new Table(container.skin); detailTable.row(); final Label labelMaxLinAcc = new Label("Max.Linear Acc.[" + characters.get(0).getMaxLinearAcceleration() + "]", container.skin); detailTable.add(labelMaxLinAcc); detailTable.row(); Slider maxLinAcc = new Slider(0, 30, .1f, false, container.skin); maxLinAcc.setValue(characters.get(0).getMaxLinearAcceleration()); maxLinAcc.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { Slider slider = (Slider)actor; for (int i = 0; i < characters.size; i++) characters.get(i).setMaxLinearAcceleration(slider.getValue()); labelMaxLinAcc.setText("Max.Linear Acc.[" + slider.getValue() + "]"); } }); detailTable.add(maxLinAcc); detailTable.row(); final Label labelProximityRadius = new Label("Proximity Radius [" + proximities.get(0).getDetectionRadius() + "]", container.skin); detailTable.add(labelProximityRadius); detailTable.row(); Slider proximityRadius = new Slider(0, 10, .1f, false, container.skin); proximityRadius.setValue(proximities.get(0).getDetectionRadius()); proximityRadius.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { Slider slider = (Slider)actor; for (int i = 0; i < proximities.size; i++) proximities.get(i).setDetectionRadius(slider.getValue()); labelProximityRadius.setText("Proximity Radius [" + slider.getValue() + "]"); } }); detailTable.add(proximityRadius); detailTable.row(); addSeparator(detailTable); detailTable.row(); final Label labelMaxLinSpeed = new Label("Max.Linear Speed.[" + characters.get(0).getMaxLinearSpeed() + "]", container.skin); detailTable.add(labelMaxLinSpeed); detailTable.row(); Slider maxLinSpeed = new Slider(0, 20, .5f, false, container.skin); maxLinSpeed.setValue(characters.get(0).getMaxLinearSpeed()); maxLinSpeed.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { Slider slider = (Slider)actor; for (int i = 0; i < characters.size; i++) characters.get(i).setMaxLinearSpeed(slider.getValue()); labelMaxLinSpeed.setText("Max.Linear Speed.[" + slider.getValue() + "]"); } }); detailTable.add(maxLinSpeed); detailTable.row(); CheckBox debug = new CheckBox("Draw Proximity", container.skin); debug.setChecked(drawDebug); debug.addListener(new ClickListener() { @Override public void clicked (InputEvent event, float x, float y) { CheckBox checkBox = (CheckBox)event.getListenerActor(); drawDebug = checkBox.isChecked(); } }); detailTable.add(debug); detailWindow = createDetailWindow(detailTable); } @Override public void update () { super.update(); // Update characters float deltaTime = GdxAI.getTimepiece().getDeltaTime(); for (int i = 0; i < characters.size; i++) { characters.get(i).update(deltaTime); } } @Override public void draw () { // Update and draw the character spriteBatch.begin(); for (int i = 0; i < characters.size; i++) { Box2dSteeringEntity character = characters.get(i); character.draw(spriteBatch); } spriteBatch.end(); if (drawDebug) { Steerable<Vector2> steerable = characters.get(0); shapeRenderer.begin(ShapeType.Line); shapeRenderer.setColor(0, 1, 0, 1); int centerX = Box2dSteeringTest.metersToPixels(steerable.getPosition().x); int centerY = Box2dSteeringTest.metersToPixels(steerable.getPosition().y); int radius = Box2dSteeringTest.metersToPixels(char0Proximity.getDetectionRadius()); shapeRenderer.circle(centerX, centerY, radius); shapeRenderer.end(); } } @Override public void dispose () { super.dispose(); shapeRenderer.dispose(); spriteBatch.dispose(); } }