概要
自動運転シミュレーションを開発している。
server,client方式に変更する。
client、書いてみた。
写真
サンプルコード
let url = "ws://localhost:50002/";
let agent = new WebSocket(url);
agent.onmessage = function(event) {
var data = JSON.parse(event.data);
draw(data.action);
};
agent.onclose = event => alert(`Closed ${event.code}`);
agent.onopen = event => alert(`open`);
agent.onerror = event => alert(`err`);
var canvas2 = document.createElement("canvas");
var ctx2 = canvas2.getContext("2d");
function c2() {
var rectWidth = 200;
var rectHeight = 110;
var rectx2 = 50;
var rectY = 130;
var cornerRadius = 50;
canvas2.width = 500;
canvas2.height = 500;
ctx2.fillStyle = "#0a0";
ctx2.strokeStyle = "#888";
ctx2.fillRect(0, 0, canvas2.width, canvas2.height);
ctx2.save();
ctx2.beginPath();
ctx2.moveTo(rectx2 - cornerRadius * .15, rectY);
ctx2.lineTo(rectx2 + rectWidth - cornerRadius, rectY);
ctx2.arcTo(rectx2 + rectWidth, rectY, rectx2 + rectWidth, rectY + cornerRadius, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth, rectY + rectHeight);
ctx2.arcTo(rectx2 + rectWidth, rectY + cornerRadius + rectHeight, rectx2, rectY + rectHeight + cornerRadius, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius, rectx2, rectY + cornerRadius + rectHeight, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius * 2 + rectHeight * 2, rectx2 + rectWidth * 2, rectY + cornerRadius + rectHeight * 2, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth + cornerRadius, rectY + cornerRadius * 1.85 + rectHeight * 2);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + cornerRadius * 1.85 + rectHeight * 2, rectx2 + rectWidth * 2, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + rectHeight, rectx2 - rectWidth, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 1.5, rectY + rectHeight, rectx2 + rectWidth, rectY - rectHeight, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth, rectY - rectHeight, rectx2, rectY, cornerRadius);
ctx2.lineTo(rectx2 + cornerRadius * .25, rectY - cornerRadius * .85);
ctx2.arcTo(rectx2 - cornerRadius * .25, rectY - cornerRadius * .25, rectx2, rectY, cornerRadius / 2);
ctx2.strokeStyle = "#f00"
ctx2.lineWidth = 40;
ctx2.stroke();
ctx2.restore()
ctx2.save()
ctx2.beginPath();
ctx2.moveTo(rectx2 - cornerRadius * .15, rectY);
ctx2.lineTo(rectx2 + rectWidth - cornerRadius, rectY);
ctx2.arcTo(rectx2 + rectWidth, rectY, rectx2 + rectWidth, rectY + cornerRadius, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth, rectY + rectHeight);
ctx2.arcTo(rectx2 + rectWidth, rectY + cornerRadius + rectHeight, rectx2, rectY + rectHeight + cornerRadius, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius, rectx2, rectY + cornerRadius + rectHeight, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius * 2 + rectHeight * 2, rectx2 + rectWidth * 2, rectY + cornerRadius + rectHeight * 2, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth + cornerRadius, rectY + cornerRadius * 1.85 + rectHeight * 2);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + cornerRadius * 1.85 + rectHeight * 2, rectx2 + rectWidth * 2, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + rectHeight, rectx2 - rectWidth,rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 1.5, rectY + rectHeight, rectx2 + rectWidth, rectY - rectHeight, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth, rectY - rectHeight, rectx2, rectY, cornerRadius);
ctx2.lineTo(rectx2 + cornerRadius * .25, rectY - cornerRadius * .85);
ctx2.arcTo(rectx2 - cornerRadius * .25, rectY - cornerRadius * .25, rectx2, rectY, cornerRadius / 2);
ctx2.lineWidth = 39;
ctx2.stroke();
ctx2.restore()
ctx2.save()
ctx2.beginPath();
ctx2.moveTo(rectx2 - cornerRadius * .15, rectY);
ctx2.lineTo(rectx2 + rectWidth - cornerRadius, rectY);
ctx2.arcTo(rectx2 + rectWidth, rectY, rectx2 + rectWidth, rectY + cornerRadius, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth, rectY + rectHeight);
ctx2.arcTo(rectx2 + rectWidth, rectY + cornerRadius + rectHeight, rectx2, rectY + rectHeight + cornerRadius, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius, rectx2, rectY + cornerRadius + rectHeight, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius * 2 + rectHeight * 2,rectx2 + rectWidth * 2, rectY + cornerRadius + rectHeight * 2, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth + cornerRadius, rectY + cornerRadius * 1.85 + rectHeight * 2);
ctx2.arcTo(rectx2 + rectWidth * 2,rectY + cornerRadius * 1.85 + rectHeight * 2, rectx2 + rectWidth * 2, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + rectHeight, rectx2 - rectWidth, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 1.5, rectY + rectHeight, rectx2 + rectWidth, rectY - rectHeight, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth, rectY - rectHeight, rectx2, rectY, cornerRadius);
ctx2.lineTo(rectx2 + cornerRadius * .25, rectY - cornerRadius * .85);
ctx2.arcTo(rectx2 - cornerRadius * .25, rectY - cornerRadius * .25, rectx2, rectY, cornerRadius / 2);
ctx2.strokeStyle = "yellow"
ctx2.lineWidth = 3;
ctx2.stroke();
ctx2.restore()
ctx2.save()
ctx2.beginPath();
ctx2.moveTo(rectx2 - cornerRadius * .15, rectY);
ctx2.lineTo(rectx2 + rectWidth - cornerRadius, rectY);
ctx2.arcTo(rectx2 + rectWidth, rectY, rectx2 + rectWidth, rectY + cornerRadius, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth, rectY + rectHeight);
ctx2.arcTo(rectx2 + rectWidth, rectY + cornerRadius + rectHeight, rectx2 , rectY + rectHeight + cornerRadius, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius, rectx2, rectY + cornerRadius + rectHeight, cornerRadius);
ctx2.arcTo(rectx2, rectY + cornerRadius * 2 + rectHeight * 2, rectx2 + rectWidth * 2, rectY + cornerRadius + rectHeight * 2, cornerRadius);
ctx2.lineTo(rectx2 + rectWidth + cornerRadius, rectY + cornerRadius * 1.85 + rectHeight * 2);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + cornerRadius * 1.85 + rectHeight * 2, rectx2 + rectWidth * 2, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 2, rectY + rectHeight, rectx2 - rectWidth, rectY, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth * 1.5, rectY + rectHeight, rectx2 + rectWidth, rectY - rectHeight, cornerRadius);
ctx2.arcTo(rectx2 + rectWidth, rectY - rectHeight, rectx2, rectY, cornerRadius);
ctx2.lineTo(rectx2 + cornerRadius * .25, rectY - cornerRadius * .85);
ctx2.arcTo(rectx2 - cornerRadius * .25, rectY - cornerRadius * .25, rectx2, rectY, cornerRadius / 2);
ctx2.strokeStyle = "#888"
ctx2.lineWidth = 2;
ctx2.stroke();
var sx = 150;
var sy = 20;
ctx2.save()
ctx2.beginPath();
ctx2.moveTo(rectx2 + sx, 314 + rectY - sy);
ctx2.lineTo(rectx2 + sx, 314 + rectY + sy);
ctx2.strokeStyle = "#f00"
ctx2.lineWidth = 2;
ctx2.stroke();
ctx2.restore()
ctx2.save()
ctx2.beginPath();
ctx2.fillStyle = "#fff"
ctx2.fillRect(rectx2 + sx - 1, 314 + rectY - sy, 1, 5)
ctx2.fillRect(rectx2 + sx, 314 + rectY - sy + 5, 1, 5)
ctx2.fillRect(rectx2 + sx - 1, 314 + rectY - sy + 10, 1, 5)
ctx2.fillRect(rectx2 + sx, 314 + rectY - sy + 15, 1, 5)
ctx2.fillRect(rectx2 + sx - 1, 314 + rectY, 1, 5)
ctx2.fillRect(rectx2 + sx, 314 + rectY + sy - 15 , 1, 5)
ctx2.fillRect(rectx2 + sx - 1, 314 + rectY + sy - 10, 1, 5)
ctx2.fillRect(rectx2 + sx, 314 + rectY + sy - 5, 1, 5)
ctx2.stroke();
ctx2.restore()
}
c2();
function kaiten(d) {
var e = document.getElementById("img1");
e.style.transform = "rotate(" + d + "deg)";
}
function sense(src, s0, s1) {
var p = 0;
for (var y = s1; y < s1 + 20; y++)
{
for (var x = s0; x < s0 + 20; x++)
{
var r = src.data[(y * 240 + x) * 4];
var g = src.data[(y * 240 + x) * 4 + 1];
var b = src.data[(y * 240 + x) * 4 + 2];
p += r + g + b;
}
}
return p / 20 / 20 / 3 / 256;
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var OFF = document.createElement("canvas");
var OFF_CTX = OFF.getContext("2d");
var FOV = Math.PI / 3;
var DEPTH = 2 * Math.tan(FOV * 0.5);
var EYE = canvas.width / DEPTH;
OFF.height = canvas.height;
OFF.width = Math.ceil(canvas.height * DEPTH);
var car = {
x: 140,
y: 440,
z: 18,
a: Math.PI * 2,
vx: 0,
vy: 0,
vz: 0,
va: 0,
px: 0,
py: 0
};
var s0 = 0.1,
s1 = 0.1,
s2 = 0.1,
s3 = 0.1,
s4 = 0.1;
function draw(r) {
car.vx = Math.cos(car.a) / 1;
car.vy = Math.sin(car.a) / 1;
car.va = 0;
if (r == 0)
{
car.va = -Math.PI / 30;
}
if (r == 1)
{
car.va = Math.PI / 30;
}
kaiten(car.va * 100);
car.x += car.vx;
car.y += car.vy;
car.a += car.va;
var horizon = Math.floor(canvas.height * 0.01);
var scale = EYE * car.z;
var yMin = Math.ceil(scale / OFF.height);
var yMax = canvas.height - horizon;
var near = scale / yMax - 1;
OFF_CTX.clearRect(0, 0, OFF.width, OFF.height);
OFF_CTX.save();
OFF_CTX.translate(OFF.width * 0.5, OFF.height + near)
OFF_CTX.rotate(Math.PI * 1.5 - car.a);
OFF_CTX.drawImage(canvas2, -car.x, -car.y);
OFF_CTX.restore();
ctx.fillRect(0, horizon, canvas.width, yMax);
for (var y = yMin; y < yMax; y += height)
{
var top = scale / y;
var width = top * DEPTH;
var height = Math.ceil(scale / Math.floor(top) - y);
var bottom = scale / (y + height);
ctx.drawImage(OFF, (OFF.width - width) * 0.5, OFF.height + near - top, width, top - bottom, 0, horizon + y, canvas.width, height);
}
var src = ctx.getImageData(0, 0, canvas.width, canvas.height);
s0 = sense(src, 30, 107);
s1 = sense(src, 70, 107);
s2 = sense(src, 110, 107);
s3 = sense(src, 150, 107);
s4 = sense(src, 190, 107);
ctx.fillStyle = "gray";
ctx.fillRect(30, 107, 20, 20);
ctx.fillRect(70, 107, 20, 20);
ctx.fillRect(110, 107, 20, 20);
ctx.fillRect(150, 107, 20, 20);
ctx.fillRect(190, 107, 20, 20);
ctx.font = "14px arial black";
var text = "a: " + Math.floor(car.a * 10);
ctx.fillText(text, 10, 12);
text = "xyz: " + Math.floor(car.x) + " " + Math.floor(car.y) + " " + Math.floor(car.z);
ctx.fillText(text, 10, 24);
ctx.fillStyle = "white";
}
function run() {
setInterval(function() {
var json = '{"observation": {"s0": "' + s0 + '", "s1": "' + s1 + '", "s2": "' + s2 + '", "s3": "' + s3 + '", "s4": "' + s4 + '" }, "reward": "1.0", "done": "false"}';
agent.send(json);
}, 100);
}
成果物
以上。