ビークルの訓練

A Pen By kanaparty

Pen Settings

Vendor Prefixing

These stylesheets will be added in this order and before the code you write in the CSS editor. You can also add another Pen here, and it will pull the CSS from it. Try typing "font" or "ribbon" below.

JavaScript Preprocessor

These scripts will run in this order and before the code in the JavaScript editor. You can also link to another Pen here, and it will run the JavaScript from it. Also try typing the name of any popular library.

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML

```            ```
<canvas id="canvas"></canvas>
```
```
!

CSS

```            ```
body{
margin : 0;
}
```
```
!

JS

```            ```
'use strict';
//変数の範囲の変更
function map(value, start1, end1, start2, end2) {
return Math.floor(start2 + (end2 - start2) * ((value - start1) / (end1 - start1)));
}
//ラジアンを返す
var PI = Math.PI;
var TWO_PI = Math.PI * 2;
return angle * PI / 180;
}
//最大値最小値を超えないように調整
function constrain(amt, low, high){
if(amt < low){
return low;
} else if(high < amt){
return high;
} else {
return amt;
}
}
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
return this;
}
//加算
if (x instanceof Vector) {
this.x += x.x;
this.y += x.y;
return this;
} else {
this.x += x;
this.y += y;
return this;
}
}
var x = vectorA.x + vectorB.x;
var y = vectorA.y + vectorB.y;
return new Vector(x, y);
}
//減算
sub(x, y) {
if (x instanceof Vector) {
this.x -= x.x;
this.y -= x.y;
return this;
} else {
this.x -= x;
this.y -= y;
return this;
}
}
static sub(vectorA, vectorB) {
var x = vectorA.x - vectorB.x;
var y = vectorA.y - vectorB.y;
return new Vector(x, y);
}
// ベクトル乗算
mult(n) {
this.x = this.x * n;
this.y = this.y * n;
return this;
}
//ベクトル除算
div(n) {
this.x = this.x / n;
this.y = this.y / n;
return this;
}
//ベクトルの大きさを返す
mag() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
//正規化する
normalize() {
var size = this.mag();
if (size === 0) {
return this;
}
this.x = this.x * (1 / size);
this.y = this.y * (1 / size);
return this;
}
//最大値
limit(max) {
if (this.mag() > max) {
return this.normalize().mult(max);
} else {
return this;
}
}
//回転
rotate(angle) {
var cos = Math.cos(angle);
var sin = Math.sin(angle);

var newX = this.x * cos - this.y * sin;
var newY = this.x * sin + this.y * cos;
this.x = newX;
this.y = newY;
return this;
}
//ベクトルの角度を返す
static angle(vectorA) {
var theta = Math.atan2(vectorA.y, vectorA.x);
return theta;
}
//長さ１のランダムな値を返す
static random2D() {
this.x = (Math.random() * 2) - 1;
this.y = (Math.random() * 2) - 1;
return this.normalize();
}
//角度から長さ１のベクトルを返す
static fromAngle(angle) {
return new Vector(Math.cos(angle), Math.sin(angle));
}
//同じ値をもったVectorを返す
static copy(vectorA) {
return new Vector(vectorA.x, vectorA.y);
}
//ベクトル内積
static dot(vectorA, vectorB) {
return vectorA.x * vectorB.x + vectorA.y * vectorB.y;
}
//ベクトル間の角度を返す
static angleBetween(vectorA, vectorB) {
var theta = Math.acos((this.dot(vectorA, vectorB)) / (vectorA.mag() * vectorB.mag()));
return theta;
}
}
class Canvas {
constructor(id, width, height, color) {
this.elm = document.getElementById(id);
this.ctx = this.elm.getContext('2d');
this.width = width;
this.height = height;
this.color = color;
this.init();
}
init() {
this.elm.width = this.width;
this.elm.height = this.height;
this.ctx.fillStyle = this.color;
this.ctx.fillRect(0, 0, this.width, this.height);
}
clear() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
repaint(color) {
this.color = color;
this.ctx.fillStyle = this.color;
this.ctx.fillRect(0, 0, this.width, this.height);
}
}
class Perceptron{
constructor(weightLength, learningConstant){
this.weightLength = weightLength;
this.weight = [];
this.c = learningConstant;
for (var i = 0; i < this.weightLength; i++) {
this.weight[i] = Math.random();
}
}
//調整
train(forces, error){
for (var i = 0; i < this.weightLength; i++) {
this.weight[i] += this.c * error.x * forces[i].x;
this.weight[i] += this.c * error.y * forces[i].y;
}
}
//合計のベクターを返す
feedfoward(forces){
var sum = new Vector(0, 0);
for (var i = 0; i < this.weightLength; i++) {
forces[i].mult(this.weight[i]);
}
return sum;
}
}
class Vehicle{
constructor(canvas, desired, targetLength){
this.position = new Vector(0,0);
this.velocity = new Vector(0,0);
this.acceleration = new Vector(0,0);
this.r = 3;
this.maxforce = 0.01;
this.maxspeed = 3;
this.brain = new Perceptron(targetLength ,0.001);
this.canvas = canvas;
this.desired = desired;
}
//状態のアップデート
update(){
this.velocity.limit(this.maxspeed);
this.acceleration.mult(0);
}
//力を適用
applyForce(force){
}
//操舵力を計算
steer(target){
var force = [];
for (var i = 0; i < target.length; i++) {
force[i] = this.seek(target[i]);
}
//ターゲットから受ける力をbrainプロパティに渡して結果をもらう
var result = this.brain.feedfoward(force);
this.applyForce(result);
//トレーニング
var error = Vector.sub(this.desired, this.position);
this.brain.train(force, error);
}
//ターゲットから受ける力を計算
seek(target){
var desired = Vector.sub(target, this.position);
desired.normalize();
desired.mult(this.maxspeed);
var steer = Vector.sub(desired, this.velocity);
steer.limit(this.maxforce);
return steer;
}
//表示
display(){
this.canvas.ctx.fillStyle = '#510340';
this.canvas.ctx.save();
this.canvas.ctx.translate(this.position.x, this.position.y);
this.canvas.ctx.beginPath();
this.canvas.ctx.rotate(Vector.angle(this.velocity));
this.canvas.ctx.moveTo(0,8);
this.canvas.ctx.lineTo(0,-8);
this.canvas.ctx.lineTo(20,0);
this.canvas.ctx.closePath();
this.canvas.ctx.fill();
this.canvas.ctx.restore();
}
//訓練のリセット
reset(){
this.brain = new Perceptron(targetLength ,0.001);
}
}
'use strict';
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var halfWindowWidth = windowWidth / 2;
var halfWindowHeight = windowHeight / 2;

//キャンバスの用意
var canvas = new Canvas('canvas', windowWidth, windowHeight, '#E3E3E0');
//目標地点の用意
var desire = new Vector(halfWindowWidth, halfWindowHeight);
//ターゲットの用意
var target = [];
var targetLength = 10;

createTarget();
function createTarget(){
for (var i = 0; i < targetLength; i++) {
var x = Math.floor(Math.random() * windowWidth);
var y = Math.floor(Math.random() * windowHeight);
target[i] = new Vector(x, y);
}
}

//ビークルの用意
var vehicle = new Vehicle(canvas, desire, targetLength);

//ターゲットを書く
function drawTarget(){
for (var i = 0; i < targetLength; i++) {
canvas.ctx.fillStyle = '#F69E38';
canvas.ctx.fillRect(target[i].x, target[i].y, 10, 10);
}
}
//目標地点
function drawDesire(){
canvas.ctx.strokeStyle="#C4C2BC";
canvas.ctx.fillStyle = "rgba(196,194,188,0.8)"
canvas.ctx.beginPath();
canvas.ctx.arc(halfWindowWidth, halfWindowHeight, 30, 0, TWO_PI, false);
canvas.ctx.closePath();
canvas.ctx.stroke();
canvas.ctx.fill();
}

//ループ
animate();
var count = 0;
function animate(){
count ++;
if(count === 1000){
createTarget();
// vehicle.reset();
count = 0;
}
//クリア
canvas.repaint('#E3E3E0');
drawDesire();
drawTarget();
vehicle.steer(target);
vehicle.update();
vehicle.display();
window.requestAnimationFrame(animate);
}

```
```
!
999px