How we integrate AI into our kid’s daily lives is an ongoing concern. The less we know the more worrying it can be.
I introduced my son to a lot of Math, Typing, Programming early. He has worked on 2D with Scratch and then 3D with various technologies from Blender to Unreal Engine and now JS (P5.JS).
By some bizarre twist of fate I have been home-schooling him on his first term of Secondary School. This has led to us working quite closely together with AI for the last 12 weeks.
Below is one of the AI projects he worked on today.
The Love Bug
Soft Body AI adjusting it’s form and effort to balance entropy HTML Code
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.1/p5.js"></script>
<meta charset="utf-8" />
<style>
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
</style>
</head>
<body>
<main>
</main>
<script>
// Declare variables for the physics calculations
let centerX = 0.0;
let centerY = 0.0;
let radius = 45;
let rotAngle = -90;
let accelX = 0.0;
let accelY = 0.0;
let deltaX = 0.0;
let deltaY = 0.0;
let springing = 0.001; // Reduced springing for less stiffness
let damping = 0.975; // Slightly increased damping for smoother motion
// Declare variables for specifying vertex locations
let nodes = 5;
let nodeStartX = [];
let nodeStartY = [];
let nodeX = [];
let nodeY = [];
let angle = [];
let frequency = [];
// Declare the variable for the curve tightness
let organicConstant = 1.0;
// Declare variables for obstacles
let obstacles = [];
// Player variables
let playerX = 0;
let playerY = 0;
let playerSpeed = 5;
// Sparks
let sparks = [];
function setup() {
createCanvas(windowWidth, windowHeight);
// Start in the center of the canvas
centerX = width / 2;
centerY = height / 2;
playerX = width / 2;
playerY = height / 2;
// Initialize arrays to 0
for (let i = 0; i < nodes; i++) {
nodeStartX[i] = 0;
nodeStartY[i] = 0;
nodeX[i] = 0;
nodeY[i] = 0;
angle[i] = 0;
}
// Initialize frequencies for corner nodes
for (let i = 0; i < nodes; i++) {
frequency[i] = random(5, 12);
}
// Add obstacles to the canvas
for (let i = 0; i < 50; i++) {
obstacles.push({
x: random(-500, 500),
y: random(-500, 500),
r: random(20, 40),
});
}
noStroke();
angleMode(DEGREES);
}
function draw() {
background(0);
// Update player position
updatePlayer();
// Draw obstacles
drawObstacles();
// Draw player
fill(0, 255, 0);
ellipse(width / 2, height / 2, 20);
// Draw and move the shape
drawShape();
moveShape();
// Update and draw sparks
updateSparks();
drawSparks();
}
function updatePlayer() {
if (keyIsDown(87)) playerY -= playerSpeed; // W
if (keyIsDown(83)) playerY += playerSpeed; // S
if (keyIsDown(65)) playerX -= playerSpeed; // A
if (keyIsDown(68)) playerX += playerSpeed; // D
}
function drawObstacles() {
fill(139,146,98);
for (let obs of obstacles) {
ellipse(obs.x - playerX + width / 2, obs.y - playerY + height / 2, obs.r * 2);
}
}
function drawShape() {
// Calculate node starting locations
for (let i = 0; i < nodes; i++) {
nodeStartX[i] = centerX + cos(rotAngle) * radius;
nodeStartY[i] = centerY + sin(rotAngle) * radius;
rotAngle += 360.0 / nodes;
}
// Draw the polygon
curveTightness(organicConstant);
let shapeColor = lerpColor(color('blue'), color('red'), organicConstant);
fill(shapeColor);
beginShape();
for (let i = 0; i < nodes; i++) {
curveVertex(nodeX[i] - playerX + width / 2, nodeY[i] - playerY + height / 2);
}
endShape(CLOSE);
}
function moveShape() {
// Move center point towards player
deltaX = playerX - centerX;
deltaY = playerY - centerY;
// Create springing effect
deltaX *= springing;
deltaY *= springing;
accelX += deltaX;
accelY += deltaY;
// Adjust center for obstacle collision
for (let obs of obstacles) {
let distToObstacle = dist(centerX, centerY, obs.x, obs.y);
if (distToObstacle < radius + obs.r) {
let overlap = radius + obs.r - distToObstacle;
let repelX = (centerX - obs.x) / distToObstacle;
let repelY = (centerY - obs.y) / distToObstacle;
// Adjust position to resolve collision
centerX += repelX * overlap * 0.5;
centerY += repelY * overlap * 0.5;
// Redirect velocity away from obstacle
accelX += repelX * 0.1;
accelY += repelY * 0.1;
}
}
// Move center
centerX += accelX;
centerY += accelY;
// Slow down springing
accelX *= damping;
accelY *= damping;
// Change curve tightness based on the overall acceleration;
// use abs() to avoid dependence on direction of acceleration
organicConstant = 1 - (abs(accelX) + abs(accelY)) * 0.2;
// Move nodes
for (let i = 0; i < nodes; i++) {
nodeX[i] = nodeStartX[i] + sin(angle[i]) * (accelX * 2);
nodeY[i] = nodeStartY[i] + sin(angle[i]) * (accelY * 2);
// Check collision with obstacles
for (let obs of obstacles) {
let distToObstacle = dist(nodeX[i], nodeY[i], obs.x, obs.y);
if (distToObstacle < obs.r) {
let overlap = obs.r - distToObstacle;
let repelForceX = (nodeX[i] - obs.x) / distToObstacle;
let repelForceY = (nodeY[i] - obs.y) / distToObstacle;
// Adjust node position
nodeX[i] += repelForceX * overlap * 0.5;
nodeY[i] += repelForceY * overlap * 0.5;
// Create sparks
createSpark(nodeX[i], nodeY[i], repelForceX, repelForceY);
}
}
angle[i] += frequency[i];
}
}
function updateSparks() {
for (let i = sparks.length - 1; i >= 0; i--) {
let spark = sparks[i];
spark.x += spark.dx;
spark.y += spark.dy;
spark.life--;
// Remove dead sparks
if (spark.life <= 0) sparks.splice(i, 1);
}
}
function createSpark(x, y, dx, dy) {
// Use the same color as the softbody shape for sparks
let sparkColor = lerpColor(color('blue'), color('red'), organicConstant);
for (let i = 0; i < 5; i++) {
sparks.push({
x: x,
y: y,
dx: dx * random(1, 3) + random(-1, 1),
dy: dy * random(1, 3) + random(-1, 1),
life: 30,
color: sparkColor // Store the color for each spark
});
}
}
function drawSparks() {
noStroke();
for (let spark of sparks) {
fill(spark.color); // Use the stored color for each spark
ellipse(spark.x - playerX + width / 2, spark.y - playerY + height / 2, 4, 4);
}
}
</script>
</body>
</html>
Fostering intelligence is a duty we take on when we become parents whether or not we work on AI
This thread is intended for parents to show off some of the positive sparks that inspire us.