当前位置: 首页 > news >正文

bubbles html5游戏源码,html5 canvas弹性气泡爆破 | 撒花动画

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

const Util = {};

Util.timeStamp = function() {

return window.performance.now();

};

Util.random = function(min, max) {

return min + Math.random() * (max - min);

};

Util.randomArray = function(array) {

return array[Math.floor(Math.random() * array.length)];

};

Util.map = function(a, b, c, d, e) {

a = this.clamp(a, b, c);

return (a - b) / (c - b) * (e - d) + d;

};

Util.lerp = function(value1, value2, amount) {

return value1 + (value2 - value1) * amount;

};

Util.clamp = function(value, min, max) {

return Math.max(min, Math.min(max, value));

};

Util.threeAngle = function(p0, p1, p2) {

var b = Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2),

a = Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2),

c = Math.pow(p2.x - p0.x, 2) + Math.pow(p2.y - p0.y, 2);

return Math.acos((a + b - c) / Math.sqrt(4 * a * b));

}

Util.hsl = function(hue, saturation, lightness) {

return `hsl(${hue},${saturation}%,${lightness}%)`;

}

class Vector {

constructor(x, y) {

this.x = x || 0;

this.y = y || 0;

}

set(x, y) {

this.x = x;

this.y = y;

}

reset() {

this.x = 0;

this.y = 0;

}

fromAngle(angle) {

let x = Math.cos(angle),

y = Math.sin(angle);

return new Vector(x, y);

}

add(vector) {

this.x += vector.x;

this.y += vector.y;

}

sub(vector) {

this.x -= vector.x;

this.y -= vector.y;

}

mult(scalar) {

this.x *= scalar;

this.y *= scalar;

}

div(scalar) {

this.x /= scalar;

this.y /= scalar;

}

dot(vector) {

return vector.x * this.x + vector.y * this.y;

}

limit(limit_value) {

if (this.mag() > limit_value) this.setMag(limit_value);

}

mag() {

return Math.hypot(this.x, this.y);

}

setMag(new_mag) {

if (this.mag() > 0) {

this.normalize();

} else {

this.x = 1;

this.y = 0;

}

this.mult(new_mag);

}

normalize() {

let mag = this.mag();

if (mag > 0) {

this.x /= mag;

this.y /= mag;

}

}

normalizedMag() {

let copy = this.copy();

copy.normalize();

return copy.mag();

}

heading() {

return Math.atan2(this.y, this.x);

}

setHeading(angle) {

let mag = this.mag();

this.x = Math.cos(angle) * mag;

this.y = Math.sin(angle) * mag;

}

dist(vector) {

return new Vector(this.x - vector.x, this.y - vector.y).mag();

}

angle(vector) {

return Math.atan2(vector.y - this.y, vector.x - this.x);

}

copy() {

return new Vector(this.x, this.y);

}

}

class Tagada {

constructor() {

this.canvas = document.createElement("canvas");

this.ctx = this.canvas.getContext('2d');

document.body.appendChild(this.canvas);

this.W = 0;

this.H = 0;

this.ressources = {

images: [],

audio: [],

}

this.backgroundColor = "gray";

this.timeData = {

now: 0,

dt: 0,

last: Util.timeStamp(),

step: 1 / 60,

};

this.frame = 0;

window.addEventListener("resize", () => {

this.setSize();

this.resize();

});

this.mouse = new Vector(0, 0);

window.addEventListener("pointermove", (event) => {

this.pMove(event);

});

}

addImage(path) {

let image = new Image();

image.src = path;

this.ressources.images.push(image);

return image;

}

drawImageCover(image, x, y, sizeX, sizeY) {

if (sizeX <= 0 || sizeY <= 0) return false;

let scaleX,

scaleY,

ratio = image.width / image.height;

let sourceScaleX, sourceScaleY;

let cRation = sizeX / sizeY;

if (cRation > ratio) {

scaleX = sizeX;

scaleY = scaleX / ratio;

sourceScaleX = image.width;

sourceScaleY = sourceScaleX / cRation;

} else {

scaleY = sizeY;

scaleX = scaleY * ratio;

sourceScaleY = image.height;

sourceScaleX = sourceScaleY * cRation;

}

let offsetX = (sizeX - scaleX);

let offsetY = (sizeY - scaleY);

this.ctx.drawImage(

image, (image.width - sourceScaleX) / 2, (image.height - sourceScaleY) / 2, sourceScaleX, sourceScaleY,

x, y, scaleX + offsetX, scaleY + offsetY

);

}

run() {

Promise.all(

this.ressources.images.map(image => {

return new Promise(resolve => {

image.onload = () => {

resolve();

}

});

})

).then(v => {

this.setSize();

this.loop();

});

}

resize() {

}

pMove(event) {

this.mouse.x = event.clientX - this.canvas.offsetLeft;

this.mouse.y = event.clientY - this.canvas.offsetTop;

}

setSize() {

this.W = this.canvas.width = window.innerWidth;

this.H = this.canvas.height = window.innerHeight;

}

update(dt) {

}

render() {

}

loop() {

this.ctx.fillStyle = this.backgroundColor;

this.ctx.fillRect(0, 0, this.W, this.H);

this.timeData.now = Util.timeStamp();

this.timeData.dt = this.timeData.dt + Math.min(1, (this.timeData.now - this.timeData.last) / 1000);

while (this.timeData.dt > this.timeData.step) {

this.timeData.dt = this.timeData.dt - this.timeData.step;

this.update(this.timeData.step);

}

this.render();

this.timeData.last = this.timeData.now;

this.frame += 1;

requestAnimationFrame(() => {

this.loop()

});

}

}

let app = new Tagada();

let shapes = [];

let $ = app.ctx;

let minSize = 0;

class Particle {

constructor(container, x, y, size) {

this.container = container;

this.position = new Vector(x, y);

this.velocity = new Vector(0, 0);

this.acceleration = new Vector(0, 0);

this.size = size;

this.maxSpeed = Util.random(100, 1000);

this.start = new Date();

this.duration = Util.random(200, 2000);

this.spinOffset = Util.random(0.001, 0.4);

this.gravity = new Vector(0, 10);

this.colors = ["#fff83a", "#ffffff"];

}

draw() {

let time = new Date() - this.start;

if (time > this.duration) {

// delete particle

let id = this.container.indexOf(this);

this.container.splice(id, 1);

}

let sizeOffset = Util.map(time, 0, this.duration, 1, 0);

$.fillStyle = this.colors[Math.floor(Util.map(Math.sin(app.frame * this.spinOffset), -1, 1, 0, this.colors.length))];

$.beginPath();

$.ellipse(this.position.x, this.position.y, this.size * sizeOffset * Math.abs(Math.sin(app.frame * this.spinOffset)), this.size * sizeOffset, this.velocity.heading(), 0, Math.PI * 2);

$.fill();

}

addForce(force) {

this.acceleration.add(force);

}

update(dt) {

this.addForce(this.gravity);

this.velocity.add(this.acceleration);

this.velocity.limit(this.maxSpeed);

this.velocity.mult(0.98);

let v = this.velocity.copy();

v.mult(dt);

this.position.add(v);

this.acceleration.reset();

}

}

class Bubble {

constructor(container, x, y, size) {

this.container = container;

this.position = new Vector(x, y);

this.velocity = new Vector(0, 0);

this.acceleration = new Vector(0, 0);

this.size = size;

this.displayedSize = size;

this.maxSpeed = Util.random(100, 400);

this.beatSpeed = Util.random(0.01, 0.04);

this.offset = Util.random(0.1, 100);

this.colors = ["#ff93c9", "#12e524"];

this.color = Util.randomArray(this.colors);

}

draw() {

this.displayedSize = this.size * Util.map(Math.sin(app.frame * this.beatSpeed), -1, 1, 0.96, 1.04);

let dMouse = this.position.dist(app.mouse);

$.strokeStyle = Util.hsl(0, Util.map(dMouse - this.displayedSize, 0, 200, 80, 0),

Util.map(dMouse - this.displayedSize, 0, 200, 60, 0)

);

// draw ondulation

let resolution = Math.floor(Util.map(this.size, 0, minSize, 6, 10));

let ps = [];

let globalSpeed = Util.map(this.velocity.mag(), 0, this.maxSpeed, 0.01, 1);

let globalScale = Util.map(this.velocity.mag(), 0, this.maxSpeed, 0.1, 1.2);

for (var i = 0; i < resolution; i++) {

let pSize = this.displayedSize + Math.sin(this.offset +

Math.cos(i * 0.46 + app.frame * 0.02) * Math.sin(-i * 2 + app.frame * 0.02)

) * this.size * globalScale;

let a = Util.map(i, 0, resolution, 0, Math.PI * 2),

x = this.position.x + Math.cos(a) * pSize,

y = this.position.y + Math.sin(a) * pSize;

//$.fillStyle = "blue";

//$.beginPath();

//$.arc(x, y, 2, 0, Math.PI * 2);

//$.fill();

ps.push({

x: x,

y: y

});

}

smooth(ps);

}

addForce(force) {

this.acceleration.add(force);

}

update(dt) {

this.divide();

this.bound();

this.velocity.add(this.acceleration);

this.velocity.limit(this.maxSpeed);

this.velocity.mult(0.98);

let v = this.velocity.copy();

v.mult(dt);

this.position.add(v);

this.acceleration.reset();

}

bound() {

let center = new Vector(app.W / 2, app.H / 2);

let dist = this.position.dist(center);

let smallestSide = Math.min(app.W, app.H) / 2;

if (dist > smallestSide) {

let force = new Vector(0, 0).fromAngle(this.position.angle(center));

force.setMag(Util.map(dist, 0, smallestSide, 0, 10));

this.addForce(force);

}

}

divide() {

let dist = this.position.dist(app.mouse);

if (dist > this.displayedSize) return;

// shake Screen

shake(Util.map(this.size, 0, minSize, 2, 8));

// delete bubble

let id = this.container.indexOf(this);

this.container.splice(id, 1);

// add Particles

let pCount = Util.map(this.size, 0, minSize, 10, 400);

for (let i = 0; i < pCount; i++) {

let angle = Util.map(i, 0, pCount, 0, Math.PI * 2),

pX = this.position.x + Math.cos(angle) * this.size,

pY = this.position.y + Math.sin(angle) * this.size;

let p = new Particle(particles, pX, pY,

Util.map(this.size, 0, minSize, 4, 10) * Util.random(0.2, 1.2));

p.velocity = new Vector().fromAngle(angle);

p.velocity.mult(Util.random(100, 800));

particles.push(p);

}

// add new bubles if size is sufficient

if (this.size < 20) return;

let divisions = Math.floor(Util.random(2, 6)),

childSize = this.size / divisions;

for (let i = 0; i < divisions; i++) {

let angle = Util.map(i, 0, divisions, 0, Math.PI * 2),

pX = this.position.x + Math.cos(angle) * this.size / 2,

pY = this.position.y + Math.sin(angle) * this.size / 2;

let bubbleChild = new Bubble(

this.container,

pX,

pY,

childSize * Util.random(0.8, 1.8)

);

bubbleChild.velocity = new Vector().fromAngle(angle);

bubbleChild.velocity.mult(Util.random(100, 400));

this.container.push(bubbleChild);

}

}

avoid(others) {

others.forEach(other => {

if (other !== this) {

let dist = this.position.dist(other.position),

max_dist = this.size + other.size;

if (max_dist - dist >= 0) {

let angle = other.position.angle(this.position);

let force = new Vector().fromAngle(angle);

force.setMag(Util.map(dist, 0, max_dist, 1, 0));

this.addForce(force);

}

}

});

}

}

function smooth(points) {

var xc = (points[0].x + points[1].x) / 2;

var yc = (points[0].y + points[1].y) / 2;

$.moveTo(xc, yc);

for (i = 1; i < points.length - 1; i++) {

var xc = (points[i].x + points[i + 1].x) / 2;

var yc = (points[i].y + points[i + 1].y) / 2;

$.quadraticCurveTo(points[i].x, points[i].y, xc, yc);

}

var xc = (points[points.length - 1].x + points[0].x) / 2;

var yc = (points[points.length - 1].y + points[0].y) / 2;

$.quadraticCurveTo(points[i].x, points[i].y, xc, yc);

var xc = (points[0].x + points[1].x) / 2;

var yc = (points[0].y + points[1].y) / 2;

$.quadraticCurveTo(points[0].x, points[0].y, xc, yc);

}

let bubbles = [],

particles = [];

// spring for the screen shake

function shake(intencity) {

let rForce = new Vector().fromAngle(Math.random() * Math.PI * 2);

rForce.setMag(intencity);

spring.velocity.add(rForce);

}

let spring = {

mass: 40,

k: 2,

damping: 0.94,

restPosition: new Vector(0, 0),

position: new Vector(0, 0),

velocity: new Vector(0, 0),

update: function() {

let force = this.position.copy();

force.sub(this.restPosition);

force.mult(-this.k);

force.div(this.mass);

this.velocity.add(force);

this.velocity.mult(this.damping);

this.velocity.limit(100);

this.position.add(this.velocity);

},

}

app.setSize();

populate();

function populate() {

minSize = Math.min(app.W, app.H) * 0.4;

particles = [];

bubbles = [];

bubbles.push(new Bubble(bubbles, app.W / 2, app.H / 2, minSize));

bubbles.push(new Bubble(bubbles, app.W / 2, app.H / 2, minSize));

}

app.resize = function() {

populate();

};

app.update = function(dt) {

spring.update();

bubbles.forEach(b => {

b.avoid(bubbles);

b.update(dt);

});

particles.forEach(p => p.update(dt));

};

app.render = function() {

$.save();

$.translate(spring.position.x, spring.position.y);

$.globalCompositeOperation = "xor";

bubbles.forEach(b => {

$.fillStyle = "#2551f3";

$.beginPath();

b.draw()

$.fill();

});

$.globalCompositeOperation = "destination-over";

bubbles.forEach(b => {

$.fillStyle = b.color;

$.beginPath();

b.draw()

$.fill();

});

$.globalCompositeOperation = "source-over";

for (let i = particles.length - 1; i > 0; i--) {

let p = particles[i];

p.draw();

}

$.restore();

};

app.backgroundColor = "#1a1a1a";

app.run();

相关文章:

  • html 页面定位失效,html5自动定位,总是定位失败,是什么原因,求指点,多谢...
  • html照片墙效果,超酷CSS3相册照片墙动画特效
  • html select 加入css样式,css为select添加样式(无脚本)实现
  • 计算机基础知识(单选题),计算机基础知识单选题
  • 桌面上计算机删除后怎么复原,电脑桌面上出现一个图标,删掉后重启桌面又恢复了?怎么才能彻底删除?...
  • 计算机日常维护小知识,计算机日常维护小常识
  • html5按钮组水平均分,ichart.js绘制虚线、平均分虚线效果的实现代码_javascript技巧...
  • 学计算机可以考统计师吗,统计师如何备考呢?
  • html 发光字,介绍几种常见发光字的制作步骤方法
  • html中元相关元素包括,tabs_panels.html
  • 计算机专业论文周进展300字,毕业设计周进展记录模板
  • 计算机网络第3班第六章,计算机网络教程第3版彭澎第6章J课件教学.ppt
  • 计算机二级数据透视图教程,计算机二级语言数据透视表做法
  • 计算机语言符号通配符,day 15 通配符和特殊符号
  • 计算机类英文参考文献,计算机英文参考文献.doc
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • axios 和 cookie 的那些事
  • bootstrap创建登录注册页面
  • linux学习笔记
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • Windows Containers 大冒险: 容器网络
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • - 概述 - 《设计模式(极简c++版)》
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 码农张的Bug人生 - 见面之礼
  • 前端面试之闭包
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 原生Ajax
  • 在weex里面使用chart图表
  • 第二十章:异步和文件I/O.(二十三)
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​卜东波研究员:高观点下的少儿计算思维
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #每日一题合集#牛客JZ23-JZ33
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (SpringBoot)第七章:SpringBoot日志文件
  • (八十八)VFL语言初步 - 实现布局
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (九)信息融合方式简介
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (一)appium-desktop定位元素原理
  • (转)linux 命令大全
  • (转)我也是一只IT小小鸟
  • (转载)Linux网络编程入门
  • (转载)利用webkit抓取动态网页和链接
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .htaccess 强制https 单独排除某个目录
  • .NET 5种线程安全集合