以下代码改编自《游戏人工智能编程案例精粹(修订版)》([美]Mat buckland,人民邮电出版社,2012)。将其C++代码改为javascript实现
<!DOCTYPE html>
<html>
<head>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="mySteerbehavior_seek.js"></script>
<style>
#world{
text-align:left;
background-color:white;
}
</style>
</head>
<body>
<canvas id='world' ></canvas>
</body>
</html>
//mysteerbehavior_seek.js
$(document).ready(function () {
var Vector2 = {
Length: function (v) {
return Math.sqrt(v.x * v.x + v.y * v.y);
},
Vector2Normal: function (v) {
var d = Math.sqrt(v.x * v.x + v.y * v.y);
return {
x: v.x / d,
y: v.y / d
};
},
Vector2Add: function (a, b) {
return {
x: a.x + b.x,
y: a.y + b.y
};
},
Vector2Sub: function (a, b) {
return {
x: a.x - b.x,
y: a.y - b.y
};
},
Vector2Mul: function (a, b) {
return {
x: a.x * b,
y: a.y * b
};
},
Vector2Div: function (a, b) {
return {
x: a.x / b,
y: a.y / b
};
},
};
var mySteeringBehavior = {
Vechile: {},
Seek: function () {
var DesiredVelocity = Vector2.Vector2Sub(this.Vechile.m_targetPos, this.Vechile.m_Pos);
return Vector2.Vector2Sub(DesiredVelocity, this.Vechile.m_Velocity);
},
Calculate: function () {
var p = this.Seek();
return p;
},
};
var Model = {
m_Pos: {
x: 100,
y: 100
},
m_Velocity: {
x: 0,
y: 0
},
m_Heading: {
x: 0,
y: 0,
angle: 0,
},
m_Mass: 1,
m_MaxSpeed: 100,
m_MaxForce: 10,
m_targetPos: {
x: 60,
y: 60
},
setTargetPos: function (pos) {
this.m_targetPos.x = pos.x;
this.m_targetPos.y = pos.y;
},
time: 0,
m_Steering: {},
Init: function () {
this.time = (new Date()).getTime();
mySteeringBehavior.Vechile = Model;
},
Update: function () {
var currentTime = (new Date()).getTime();
var time_elapsed = currentTime - Model.time;
this.time = currentTime;
time_elapsed /= 1000;
var force = mySteeringBehavior.Calculate();
var acceleration = Vector2.Vector2Div(force, Model.m_Mass);
var dVelocity = Vector2.Vector2Mul(acceleration, time_elapsed);
Model.m_Velocity = Vector2.Vector2Add(Model.m_Velocity, dVelocity);
var len = Vector2.Length(Model.m_Velocity);
if (len > Model.m_MaxSpeed) {
Model.m_Velocity = Vector2.Vector2Mul(Vector2.Vector2Normal(Model.m_Velocity), Model.m_MaxSpeed);
}
var dPos = Vector2.Vector2Mul(Model.m_Velocity, time_elapsed);
Model.m_Pos = Vector2.Vector2Add(Model.m_Pos, dPos);
len = Vector2.Length(Model.m_Velocity);
if (len > 0.1) {
Model.m_Heading.angle = Math.atan2(Model.m_Velocity.y, Model.m_Velocity.x);
console.log("change-" + Model.m_Heading.angle);
}
console.log(":" + len);
},
};
var View = {
world: null,
canvas: null,
world_width: 0,
world_height: 0,
Init: function () {
this.world = document.getElementById("world");
this.world_width = document.documentElement.clientWidth;
this.world_height = document.documentElement.clientHeight;
this.world.width = document.documentElement.clientWidth;
this.world.height = document.documentElement.clientHeight;
this.canvas = this.world.getContext("2d");
},
Show_Info: function (info) {
this.canvas.font = "30px Arial";
this.canvas.fillText(info.info, info.x, info.y);
},
draw_car: function () {
this.canvas.strokeStyle = "rgb(0,0,255)";
var pos = Model.m_Pos;
var angle = Model.m_Heading.angle;
this.canvas.translate(pos.x, pos.y);
this.canvas.rotate(angle);
View.canvas.clearRect(-35, -35, 70, 70);
this.canvas.beginPath();
this.canvas.moveTo(0, -10);
this.canvas.lineTo(30, 0);
this.canvas.lineTo(0, 10);
this.canvas.closePath();
this.canvas.stroke();
this.canvas.rotate(-angle);
this.canvas.translate(-pos.x, -pos.y);
},
draw_cross: function () {
this.canvas.strokeStyle = "rgb(255,0,0)";
var pos = Model.m_targetPos;
this.canvas.translate(pos.x, pos.y);
//View.canvas.clearRect(-10, 10, 20, 20);
this.canvas.beginPath();
this.canvas.moveTo(-10, 0);
this.canvas.lineTo(10, 0);
this.canvas.moveTo(0, -10);
this.canvas.lineTo(0, 10);
this.canvas.arc(0, 0, 6, 0, 2 * Math.PI, false);
this.canvas.stroke();
this.canvas.translate(-pos.x, -pos.y);
},
View: function () {
this.draw_car();
this.draw_cross();
},
};
var Controller = {
timer: null,
Init: function () {
Model.Init();
View.Init();
$("#world").mousedown(Controller.click);
Controller.timer = setInterval(function () {
Controller.Update();
}, 40);
},
Update: function () {
Model.Update();
View.View();
},
click: function (e) {
Model.setTargetPos({
x: e.offsetX,
y: e.offsetY
});
View.canvas.clearRect(0, 0, View.world_width, View.world_height);
},
};
Controller.Init();
});