Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
Lecture 3 code
  • Loading branch information
gniziemazity authored Mar 18, 2022
1 parent c981ded commit e84f82e
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 0 deletions.
80 changes: 80 additions & 0 deletions 3. Artificial sensors/car.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
class Car{
constructor(x,y,width,height){
this.x=x;
this.y=y;
this.width=width;
this.height=height;

this.speed=0;
this.acceleration=0.2;
this.maxSpeed=3;
this.friction=0.05;
this.angle=0;

this.sensor=new Sensor(this);
this.controls=new Controls();
}

update(roadBorders){
this.#move();
this.sensor.update(roadBorders);
}

#move(){
if(this.controls.forward){
this.speed+=this.acceleration;
}
if(this.controls.reverse){
this.speed-=this.acceleration;
}

if(this.speed>this.maxSpeed){
this.speed=this.maxSpeed;
}
if(this.speed<-this.maxSpeed/2){
this.speed=-this.maxSpeed/2;
}

if(this.speed>0){
this.speed-=this.friction;
}
if(this.speed<0){
this.speed+=this.friction;
}
if(Math.abs(this.speed)<this.friction){
this.speed=0;
}

if(this.speed!=0){
const flip=this.speed>0?1:-1;
if(this.controls.left){
this.angle+=0.03*flip;
}
if(this.controls.right){
this.angle-=0.03*flip;
}
}

this.x-=Math.sin(this.angle)*this.speed;
this.y-=Math.cos(this.angle)*this.speed;
}

draw(ctx){
ctx.save();
ctx.translate(this.x,this.y);
ctx.rotate(-this.angle);

ctx.beginPath();
ctx.rect(
-this.width/2,
-this.height/2,
this.width,
this.height
);
ctx.fill();

ctx.restore();

this.sensor.draw(ctx);
}
}
45 changes: 45 additions & 0 deletions 3. Artificial sensors/controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Controls{
constructor(){
this.forward=false;
this.left=false;
this.right=false;
this.reverse=false;

this.#addKeyboardListeners();
}

#addKeyboardListeners(){
document.onkeydown=(event)=>{
switch(event.key){
case "ArrowLeft":
this.left=true;
break;
case "ArrowRight":
this.right=true;
break;
case "ArrowUp":
this.forward=true;
break;
case "ArrowDown":
this.reverse=true;
break;
}
}
document.onkeyup=(event)=>{
switch(event.key){
case "ArrowLeft":
this.left=false;
break;
case "ArrowRight":
this.right=false;
break;
case "ArrowUp":
this.forward=false;
break;
case "ArrowDown":
this.reverse=false;
break;
}
}
}
}
15 changes: 15 additions & 0 deletions 3. Artificial sensors/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<head>
<title>Self-driving car - No libraries</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="myCanvas"></canvas>
<script src="sensor.js"></script>
<script src="utils.js"></script>
<script src="road.js"></script>
<script src="controls.js"></script>
<script src="car.js"></script>
<script src="main.js"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions 3. Artificial sensors/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const canvas=document.getElementById("myCanvas");
canvas.width=200;

const ctx = canvas.getContext("2d");
const road=new Road(canvas.width/2,canvas.width*0.9);
const car=new Car(road.getLaneCenter(1),100,30,50);

animate();

function animate(){
car.update(road.borders);

canvas.height=window.innerHeight;

ctx.save();
ctx.translate(0,-car.y+canvas.height*0.7);

road.draw(ctx);
car.draw(ctx);

ctx.restore();
requestAnimationFrame(animate);
}
56 changes: 56 additions & 0 deletions 3. Artificial sensors/road.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
class Road{
constructor(x,width,laneCount=3){
this.x=x;
this.width=width;
this.laneCount=laneCount;

this.left=x-width/2;
this.right=x+width/2;

const infinity=1000000;
this.top=-infinity;
this.bottom=infinity;

const topLeft={x:this.left,y:this.top};
const topRight={x:this.right,y:this.top};
const bottomLeft={x:this.left,y:this.bottom};
const bottomRight={x:this.right,y:this.bottom};
this.borders=[
[topLeft,bottomLeft],
[topRight,bottomRight]
];
}

getLaneCenter(laneIndex){
const laneWidth=this.width/this.laneCount;
return this.left+laneWidth/2+
Math.min(laneIndex,this.laneCount-1)*laneWidth;
}

draw(ctx){
ctx.lineWidth=5;
ctx.strokeStyle="white";

for(let i=1;i<=this.laneCount-1;i++){
const x=lerp(
this.left,
this.right,
i/this.laneCount
);

ctx.setLineDash([20,20]);
ctx.beginPath();
ctx.moveTo(x,this.top);
ctx.lineTo(x,this.bottom);
ctx.stroke();
}

ctx.setLineDash([]);
this.borders.forEach(border=>{
ctx.beginPath();
ctx.moveTo(border[0].x,border[0].y);
ctx.lineTo(border[1].x,border[1].y);
ctx.stroke();
});
}
}
100 changes: 100 additions & 0 deletions 3. Artificial sensors/sensor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
class Sensor{
constructor(car){
this.car=car;
this.rayCount=5;
this.rayLength=150;
this.raySpread=Math.PI/2;

this.rays=[];
this.readings=[];
}

update(roadBorders){
this.#castRays();
this.readings=[];
for(let i=0;i<this.rays.length;i++){
this.readings.push(
this.#getReading(this.rays[i],roadBorders)
);
}
}

#getReading(ray,roadBorders){
let touches=[];

for(let i=0;i<roadBorders.length;i++){
const touch=getIntersection(
ray[0],
ray[1],
roadBorders[i][0],
roadBorders[i][1]
);
if(touch){
touches.push(touch);
}
}

if(touches.length==0){
return null;
}else{
const offsets=touches.map(e=>e.offset);
const minOffset=Math.min(...offsets);
return touches.find(e=>e.offset==minOffset);
}
}

#castRays(){
this.rays=[];
for(let i=0;i<this.rayCount;i++){
const rayAngle=lerp(
this.raySpread/2,
-this.raySpread/2,
this.rayCount==1?0.5:i/(this.rayCount-1)
)+this.car.angle;

const start={x:this.car.x, y:this.car.y};
const end={
x:this.car.x-
Math.sin(rayAngle)*this.rayLength,
y:this.car.y-
Math.cos(rayAngle)*this.rayLength
};
this.rays.push([start,end]);
}
}

draw(ctx){
for(let i=0;i<this.rayCount;i++){
let end=this.rays[i][1];
if(this.readings[i]){
end=this.readings[i];
}

ctx.beginPath();
ctx.lineWidth=2;
ctx.strokeStyle="yellow";
ctx.moveTo(
this.rays[i][0].x,
this.rays[i][0].y
);
ctx.lineTo(
end.x,
end.y
);
ctx.stroke();

ctx.beginPath();
ctx.lineWidth=2;
ctx.strokeStyle="black";
ctx.moveTo(
this.rays[i][1].x,
this.rays[i][1].y
);
ctx.lineTo(
end.x,
end.y
);
ctx.stroke();
}
}
}
9 changes: 9 additions & 0 deletions 3. Artificial sensors/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
body{
margin:0;
background:darkgray;
overflow:hidden;
text-align:center;
}
#myCanvas{
background:lightgray;
}
23 changes: 23 additions & 0 deletions 3. Artificial sensors/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function lerp(A,B,t){
return A+(B-A)*t;
}

function getIntersection(A,B,C,D){
const tTop=(D.x-C.x)*(A.y-C.y)-(D.y-C.y)*(A.x-C.x);
const uTop=(C.y-A.y)*(A.x-B.x)-(C.x-A.x)*(A.y-B.y);
const bottom=(D.y-C.y)*(B.x-A.x)-(D.x-C.x)*(B.y-A.y);

if(bottom!=0){
const t=tTop/bottom;
const u=uTop/bottom;
if(t>=0 && t<=1 && u>=0 && u<=1){
return {
x:lerp(A.x,B.x,t),
y:lerp(A.y,B.y,t),
offset:t
}
}
}

return null;
}

0 comments on commit e84f82e

Please sign in to comment.