This tutorial shows an HTML5 implementation of the Seek Steering Behavior in which a vehicle (seeker) moves in a realistic manner toward a target using the seek algorithm.
The Steering Behaviors are artificial intelligence algorithms which allow autonomous characters to move in a realistic manner. They are developed by Craig Reynolds. More about the theory of steering behaviors algorithms you can find in his papers.
The first steering behavior which will be discussed here is the seek algorithm. Its presentation is divided into next three sections:
- a simple live demo programmed in HTML5 using Phaser framework
- images with used math vectors and a pseudo-code explanation
- full source code listing which is also available for download on Github
Live Demo
The green arrow (seeker) seeks the blue circle (target) and moves toward it. Use your mouse to move the blue circle (target) on some other location.
Vectors and pseudo-code
Steps 1-3: Calculating the desired velocity
- 1. Vector (desired velocity) = Position (target) – Position (vehicle)
- 2. Normalize Vector (desired velocity)
- 3. Scale Vector (desired velocity) to the maximum speed
Steps 4-5: Calculating the steering force
- 4. Vector (steering force) = Vector (desired velocity) – Vector (current velocity)
- 5. Limit the magnitude of Vector (steering force) to the maximum force
Steps 6-7: Calculating the vehicle’s new velocity
- 6. Vector (new velocity) = Vector (current velocity) + Vector (steering force)
- 7. Limit the magnitude of Vector (new velocity) to the maximum speed
The source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
window.onload = function() { var game = new Phaser.Game( 800, 480, Phaser.CANVAS, '', {preload: preload, create: create, update: update} ); var vecReference = new Phaser.Point(0, 0); var sprSeeker; var sprTarget; function preload() { game.load.image('imgSeeker', 'assets/arrow_green.png'); game.load.image('imgTarget', 'assets/circle_blue.png'); } function create(){ // set the scale mode to cover the entire screen this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; this.scale.pageAlignVertically = true; this.scale.pageAlignHorizontally = true; // set the background color of the stage game.stage.backgroundColor = "#ccc"; // start the Phaser arcade physics engine game.physics.startSystem(Phaser.Physics.ARCADE); // create seeker sprite sprSeeker = game.add.sprite(game.world.centerX, game.world.centerY, 'imgSeeker'); sprSeeker.anchor.setTo(0.5, 0.5); game.physics.enable(sprSeeker, Phaser.Physics.ARCADE); sprSeeker.MAX_SPEED = 240; sprSeeker.MAX_STEER = 6; sprSeeker.MAX_SPEED_SQ = sprSeeker.MAX_SPEED * sprSeeker.MAX_SPEED; sprSeeker.MAX_STEER_SQ = sprSeeker.MAX_STEER * sprSeeker.MAX_STEER; // create target sprite sprTarget = game.add.sprite(game.input.x, game.input.y, 'imgTarget'); sprTarget.anchor.setTo(0.5, 0.5); } function update(){ // update target position regarding to the current input control position sprTarget.position.setTo(game.input.x, game.input.y); // update seeker to move toward the target seek(sprSeeker, sprTarget); } /** * Updates vehicle velocity so that it moves toward the target. */ function seek(pVehicle, pTarget){ var vecDesired; // 1. vector(desired velocity) = (target position) - (vehicle position) vecDesired = Phaser.Point.subtract(pTarget.position, pVehicle.position); // 2. normalize vector(desired velocity) vecDesired.normalize(); // 3. scale vector(desired velocity) to maximum speed vecDesired.multiply(pVehicle.MAX_SPEED, pVehicle.MAX_SPEED); // 4. vector(steering force) = vector(desired velocity) - vector(current velocity) var vecSteer = Phaser.Point.subtract(vecDesired, pVehicle.body.velocity); // 5. limit the magnitude of vector(steering force) to maximum force if (vecSteer.getMagnitudeSq() > pVehicle.MAX_STEER_SQ){ vecSteer.setMagnitude(pVehicle.MAX_STEER); } // 6. vector(new velocity) = vector(current velocity) + vector(steering force) pVehicle.body.velocity.add(vecSteer.x, vecSteer.y); // 7. limit the magnitude of vector(new velocity) to maximum speed if (pVehicle.body.velocity.getMagnitudeSq() > pVehicle.MAX_SPEED_SQ){ pVehicle.body.velocity.setMagnitude(pVehicle.MAX_SPEED); } // 8. update vehicle rotation according to the angle of the vehicle velocity pVehicle.rotation = vecReference.angle(pVehicle.body.velocity); } } |
hello! nice demo, did you implemented arrival behavior? I am having stability problems
Well, I started with implementing all steering behaviors but then I gave up after the first part and a low interest for it.