Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

У Вас число превысит максимальное число int. Можно использовать в Вашем случае uint, но лучше все переписать на double.
Добавление к программе строки glutReshapeFunc(changeSize); приводит к тому, что треугольник перестаёт совсем отрисовываться.
Выдаёт ошибку glut32.dll не найден! При том, что он лежит в System32! Всё решил) Нужно отправить не в System32, а в System.
Спасибо за статью. Я не Ваш студент. Но мне она помогла написать функцию для Канторова множества на Python для черепашки: import turtle def kanter(x, y, d):     if d > 1:         turtle...
Как реализовать в данном примере границы расчёта?

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Статья по теме: 
Демо JavaScript: 

<canvas width="500" height="500"></canvas>

let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = "yellow";
ctx.strokeStyle = "yellow";
 
 
class Vector{
	constructor(x, y){
		this.x = x || 0;
		this.y = y || 0;
	}
	add(vector){ //Сложить два вектора
		this.x += vector.x;
		this.y += vector.y;
	}
	getMagnitude(){ //Получить длину вектора
		return Math.sqrt(this.x * this.x + this.y * this.y);
	}
	getAngle(){ //Получить угол вектора
		return Math.atan2(this.y,this.x);
	}
	static fromAngle(angle, magnitude){ //Получить новый вектор исходя из угла и размеров
		return new Vector(magnitude * Math.cos(angle), magnitude * Math.sin(angle));
	}
}
class Particle{
	constructor(point, speed, acceleration){
		this.position = point || new Vector(0, 0);
		this.speed = speed || new Vector(0, 0);
		this.acceleration = acceleration || new Vector(0, 0);
		this.size = 1;
		this.color = "#ff0";
	}
	move(){ //Двигать частицы
		//Добавить ускорение к скорости
		this.speed.add(this.acceleration);
		//Добавить скорость к координатам
		this.position.add(this.speed);
	}
	submitToFields(){ //Влияние гравитационных полей на частицу
		// стартовое ускорение в кадре
		let totalAcceleration = new Vector(0, 0)
		//Цикл по гравитационным полям
		fields.forEach((field)=>{
			//Расстояние от гравитационного поля до частицы.
			let vector = new Vector(field.position.x - this.position.x, field.position.y - this.position.y);
			let force = field.mass / Math.pow(vector.x*vector.x+vector.y*vector.y,1.5);
			//Аккумулируем ускорение в кадре произведением силы на расстояние
			totalAcceleration.add(new Vector(vector.x * force, vector.y * force));
		})
		//Обновляем ускорение частицы
		this.acceleration = totalAcceleration;
	}
}
class Emitter{ //Излучатели частиц
	constructor(point, speed, spread){
		this.position = point;
		this.speed = speed;
		this.spread = spread || Math.PI / 32; //Возможный угол = скорость +/- разброс.
		this.color = "#70f";
	}
	emitParticle(){ //Создание новой частицы по параметрам излучателя
		// Использование случайного угла для формирования потока частиц позволит нам получить своего рода "спрей";
		let angle = this.speed.getAngle() + this.spread - (Math.random() * this.spread * 2);
		//Магнитуда скорости излучателя
		let magnitude = this.speed.getMagnitude();
		//Координаты излучателя
		let position = new Vector(this.position.x, this.position.y);
		// Обновлённая скорость, полученная из вычисленного угла и магнитуды
		let speed = Vector.fromAngle(angle, magnitude);
		//Возвращаем частицу
		return new Particle(position, speed);
	}
}
class Field{
	constructor(point, mass){
		this.position = point;
		this.color = "#00a";
		this.mass = mass;	
	}
	set mass(mass){ //Сеттер. Вызывается при попытке записать что-то в this.mass;
		this.massValue = mass;
		this.color = mass < 0 ? "#a00" : "#aa0";
	}
	get mass(){ //Геттер. Вызывается при попытке получить значение из this.mass. В качестве значения отдаcт this.massValue
		return this.massValue;
	}
}
let midX = canvas.width/2;
let midY = canvas.height/2;
var particles = [];
var emitters = [
  new Emitter(new Vector(midX + 50, midY), Vector.fromAngle(6, 2))
];
var fields = [
  new Field(new Vector(midX + 100, midY + 20), 150),
  new Field(new Vector(midX - 100, midY + 20), 100),
  new Field(new Vector(midX, midY + 20), -20),
];
var maxParticles = 2000; //Максимальное кол-во отображаемых частиц
var emissionRate = 4;	//Количество частиц излучаемых за кадр
function play(){
	update();	
	render();
	requestAnimationFrame(play);
}
play();
function update(){
	addNewParticles(); //Добавляем частицы в массив
	plotParticles(canvas.width, canvas.height); //Заставляем частицы двигаться
 
}
function render(){
	ctx.fillStyle = "black"
	ctx.fillRect(0,0, canvas.width, canvas.height);
	drawParticles();
	drawEmitters();
	drawFields();
}
function addNewParticles(){
	if(particles.length >= maxParticles) return;
	for(let i in emitters){
		for(let j = 0; j < emissionRate; j++){
			particles.push(emitters[i].emitParticle());
		}
	}
}
function plotParticles(boundX, boundY){
	let currentParticles = [];
	for(let i in particles){
		let particle = particles[i];
		let pos = particle.position;
		let flag = false; //Если частица за пределами или попала в одно из гравитационных полей, то пропускаем ее и переходим к следующей.
		if(pos.x < 0 || pos.x > boundX || pos.y < 0 || pos.y > boundY) flag = true;
		for(j in fields){
			if(Math.abs(fields[j].position.x - particles[i].position.x) < 5 && Math.abs(fields[j].position.y - particles[i].position.y)< 5) flag = true;
		}
		if(flag) continue;
		particle.submitToFields()
		particle.move();
		currentParticles.push(particle);
	}
	// Замена глобального массива частиц на массив без вылетевших за пределы холста частиц
	particles = currentParticles;
}
function drawParticles(){
	particles.forEach((particle)=>{
		ctx.fillStyle = particle.color;
		ctx.fillRect(particle.position.x, particle.position.y, particle.size, particle.size);
	});
}
function drawEmitters(){
	emitters.forEach((emitter)=>{
		ctx.fillStyle = emitter.color;
		ctx.beginPath();
		ctx.arc(emitter.position.x, emitter.position.y, 5, 0, 2 * Math.PI);
		ctx.closePath();
		ctx.fill();
	});
}
function drawFields(){
	fields.forEach((field)=>{
		var gradient1 = ctx.createRadialGradient(field.position.x, field.position.y, Math.abs(field.mass)/2, field.position.x, field.position.y, 0);
		gradient1.addColorStop(0,"rgba(0, 0, 0, 0)");
		gradient1.addColorStop(1, field.color);
		ctx.fillStyle = gradient1;
		ctx.fillRect(field.position.x-Math.abs(field.mass)/2, field.position.y-Math.abs(field.mass)/2, Math.abs(field.mass), Math.abs(field.mass));
	})
}