1658 lines
47 KiB
JavaScript
1658 lines
47 KiB
JavaScript
import { lib, game, ui, get, ai, _status } from "../../noname.js";
|
||
game.import("play", function () {
|
||
return {
|
||
name: "coin",
|
||
init: function () {
|
||
if (
|
||
lib.config.mode != "chess" ||
|
||
get.config("chess_mode") != "leader"
|
||
) {
|
||
_status.coin = 0;
|
||
}
|
||
},
|
||
arenaReady: function () {
|
||
if (_status.video || _status.connectMode) return;
|
||
if (
|
||
lib.config.mode != "chess" ||
|
||
get.config("chess_mode") != "leader"
|
||
) {
|
||
var str;
|
||
if (lib.config.coin_display_playpackconfig == "text") {
|
||
str = "<span>" + lib.config.coin + "</span><span>金</span>";
|
||
} else {
|
||
str =
|
||
'<span style="position:absolute">㉤</span><span style="margin-left:18px;font-family:xinwei;line-height:10px">' +
|
||
lib.config.coin +
|
||
"</span>";
|
||
}
|
||
if (lib.config.coin_canvas_playpackconfig) {
|
||
ui.window.classList.add("canvas_top");
|
||
}
|
||
ui.coin = ui.create.system(str, null, true);
|
||
if (lib.config.snowFall) {
|
||
game.haveFun.list.snow.bought = true;
|
||
setTimeout(function () {
|
||
game.haveFun.snow();
|
||
}, 500);
|
||
}
|
||
lib.setPopped(
|
||
ui.coin,
|
||
function () {
|
||
var uiintro = ui.create.dialog("hidden");
|
||
uiintro.classList.add("coin_menu");
|
||
uiintro.add("商店");
|
||
uiintro.listen(function (e) {
|
||
e.stopPropagation();
|
||
});
|
||
var clickBuy = function () {
|
||
if (this.innerHTML == "停止") {
|
||
game.haveFun[this.name + "Stop"]();
|
||
} else if (this.innerHTML == "开始") {
|
||
game.haveFun[this.name]();
|
||
} else if (this.innerHTML.indexOf("金") != -1) {
|
||
if (lib.config.coin >= this.content.cost) {
|
||
this.content.bought = true;
|
||
game.changeCoin(-this.content.cost);
|
||
game.haveFun[this.name]();
|
||
if (this.content.onbuy) {
|
||
this.content.onbuy.call(this);
|
||
}
|
||
} else {
|
||
return;
|
||
}
|
||
}
|
||
ui.click.window();
|
||
};
|
||
for (var i in game.haveFun.list) {
|
||
var item = game.haveFun.list[i];
|
||
uiintro.add(
|
||
'<div class="coin_buy">' +
|
||
item.name +
|
||
'<div class="menubutton">' +
|
||
item.cost +
|
||
"金</span></div></div>"
|
||
);
|
||
var buy =
|
||
uiintro.content.lastChild.lastChild.lastChild;
|
||
if (lib.config.coin < item.cost && !item.bought) {
|
||
buy.classList.add("disabled");
|
||
}
|
||
if (item.bought) {
|
||
if (item.running) {
|
||
buy.innerHTML = "停止";
|
||
if (item.control) {
|
||
var node = item.control();
|
||
if (node) {
|
||
buy.parentNode.appendChild(
|
||
node,
|
||
buy
|
||
);
|
||
}
|
||
}
|
||
} else {
|
||
buy.innerHTML = "开始";
|
||
}
|
||
}
|
||
buy.name = i;
|
||
buy.content = item;
|
||
buy.listen(clickBuy);
|
||
}
|
||
|
||
if (!game.phaseNumber && !game.online) {
|
||
uiintro.add("下注");
|
||
uiintro.add(
|
||
'<div class="coin_buy">本局获胜<div class="menubutton">20金</span></div></div>'
|
||
);
|
||
var bet =
|
||
uiintro.content.lastChild.lastChild.lastChild;
|
||
bet.listen(function () {
|
||
if (_status.betWin) return;
|
||
_status.betWin = true;
|
||
game.changeCoin(-20);
|
||
this.innerHTML = "已下注";
|
||
});
|
||
if (_status.betWin) {
|
||
bet.innerHTML = "已下注";
|
||
}
|
||
} else if (_status.betWin) {
|
||
uiintro.add("下注");
|
||
uiintro.add(
|
||
'<div class="coin_buy">本局获胜<div class="menubutton">已下注</span></div></div>'
|
||
);
|
||
}
|
||
|
||
uiintro.classList.add("noleave");
|
||
|
||
return uiintro;
|
||
},
|
||
220,
|
||
400
|
||
);
|
||
}
|
||
},
|
||
game: {
|
||
changeCoin: function (num, toast, audio) {
|
||
if (typeof num == "number" && ui.coin) {
|
||
if (num != 0 && toast !== false) {
|
||
ui.create.toast(
|
||
`${num > 0 ? "获得" : "花费"} ${Math.abs(
|
||
num
|
||
)} 金币`
|
||
);
|
||
}
|
||
if (audio !== false) {
|
||
game.playAudio(
|
||
"effect",
|
||
num > 0 ? "coin" : "coin_cost"
|
||
);
|
||
}
|
||
game.saveConfig("coin", lib.config.coin + num);
|
||
var str;
|
||
if (lib.config.coin_display_playpackconfig == "text") {
|
||
str =
|
||
"<span>" +
|
||
lib.config.coin +
|
||
"</span><span>金</span>";
|
||
} else {
|
||
str =
|
||
'<span style="position:absolute">㉤</span><span style="margin-left:18px;font-family:xinwei;line-height:10px">' +
|
||
lib.config.coin +
|
||
"</span>";
|
||
}
|
||
ui.coin.innerHTML = str;
|
||
}
|
||
},
|
||
haveFun: {
|
||
list: {
|
||
firework: {
|
||
name: "烟花",
|
||
cost: 50,
|
||
},
|
||
snow: {
|
||
name: "下雪",
|
||
cost: 20,
|
||
size: "large",
|
||
control: function () {
|
||
var size = ui.create.div(".menubutton");
|
||
if (game.haveFun.list.snow.size == "small") {
|
||
size.innerHTML = "大雪";
|
||
} else {
|
||
size.innerHTML = "小雪";
|
||
}
|
||
size.listen(game.haveFun.snowSize);
|
||
return size;
|
||
},
|
||
},
|
||
star: {
|
||
name: "星云",
|
||
cost: 10,
|
||
},
|
||
blink: {
|
||
name: "闪烁",
|
||
cost: 10,
|
||
},
|
||
},
|
||
alwaysSnow: function () {
|
||
game.saveConfig("snowFall", !lib.config.snowFall);
|
||
game.reload();
|
||
},
|
||
blink: function () {
|
||
if (game.haveFun.list.blink.running) return;
|
||
game.haveFun.list.blink.running = true;
|
||
if (game.haveFun.blinkLoop) {
|
||
game.haveFun.blinkLoop();
|
||
} else {
|
||
var canvas = document.createElement("canvas");
|
||
ui.window.appendChild(canvas);
|
||
canvas.classList.add("fun");
|
||
canvas.style.zIndex = 20;
|
||
var ctx = canvas.getContext("2d");
|
||
|
||
//Make the canvas occupy the full page
|
||
var W = ui.window.offsetWidth,
|
||
H = ui.window.offsetHeight;
|
||
canvas.width = W;
|
||
canvas.height = H;
|
||
lib.onresize.push(function () {
|
||
var W = ui.window.offsetWidth,
|
||
H = ui.window.offsetHeight;
|
||
canvas.width = W;
|
||
canvas.height = H;
|
||
});
|
||
|
||
var particles = [];
|
||
var mouse = {};
|
||
|
||
//Lets create some particles now
|
||
var particle_count = 25;
|
||
|
||
//finally some mouse tracking
|
||
ui.window.addEventListener("mousemove", function (e) {
|
||
//since the canvas = full page the position of the mouse
|
||
//relative to the document will suffice
|
||
mouse.x = e.pageX / game.documentZoom;
|
||
mouse.y = e.pageY / game.documentZoom;
|
||
});
|
||
ui.window.addEventListener("touchmove", function (e) {
|
||
mouse.x = e.touches[0].clientX / game.documentZoom;
|
||
mouse.y = e.touches[0].clientY / game.documentZoom;
|
||
});
|
||
|
||
var particle = function () {
|
||
//speed, life, location, life, colors
|
||
//speed.x range = -2.5 to 2.5
|
||
//speed.y range = -15 to -5 to make it move upwards
|
||
//lets change the Y speed to make it look like a flame
|
||
this.speed = {
|
||
x: -2.5 + Math.random() * 5,
|
||
y: -5 + Math.random() * 10,
|
||
};
|
||
this.speed.x /= 4;
|
||
this.speed.y /= 4;
|
||
//location = mouse coordinates
|
||
//Now the flame follows the mouse coordinates
|
||
if (mouse.x && mouse.y) {
|
||
this.location = { x: mouse.x, y: mouse.y };
|
||
} else {
|
||
this.location = { x: W / 2, y: H / 2 };
|
||
}
|
||
//radius range = 10-30
|
||
this.radius = 10 + Math.random() * 20;
|
||
//life range = 20-30
|
||
this.radius /= 4;
|
||
this.life = 20 + Math.random() * 10;
|
||
this.life *= 4;
|
||
this.remaining_life = this.life;
|
||
//colors
|
||
this.r = Math.round(Math.random() * 255);
|
||
this.g = Math.round(Math.random() * 255);
|
||
this.b = Math.round(Math.random() * 255);
|
||
};
|
||
for (var i = 0; i < particle_count; i++) {
|
||
particles.push(new particle());
|
||
}
|
||
|
||
var draw = function () {
|
||
if (!game.haveFun.list.blink.running) {
|
||
canvas.width = W;
|
||
canvas.height = H;
|
||
return;
|
||
}
|
||
ctx.clearRect(0, 0, W, H);
|
||
//Painting the canvas black
|
||
//Time for lighting magic
|
||
//particles are painted with "lighter"
|
||
//In the next frame the background is painted normally without blending to the
|
||
//previous frame
|
||
ctx.globalCompositeOperation = "lighter";
|
||
|
||
for (var i = 0; i < particles.length; i++) {
|
||
var p = particles[i];
|
||
ctx.beginPath();
|
||
//changing opacity according to the life.
|
||
//opacity goes to 0 at the end of life of a particle
|
||
p.opacity =
|
||
Math.round(
|
||
(p.remaining_life / p.life) * 100
|
||
) / 100;
|
||
//a gradient instead of white fill
|
||
var gradient = ctx.createRadialGradient(
|
||
p.location.x,
|
||
p.location.y,
|
||
0,
|
||
p.location.x,
|
||
p.location.y,
|
||
p.radius
|
||
);
|
||
gradient.addColorStop(
|
||
0,
|
||
"rgba(" +
|
||
p.r +
|
||
", " +
|
||
p.g +
|
||
", " +
|
||
p.b +
|
||
", " +
|
||
p.opacity +
|
||
")"
|
||
);
|
||
gradient.addColorStop(
|
||
0.5,
|
||
"rgba(" +
|
||
p.r +
|
||
", " +
|
||
p.g +
|
||
", " +
|
||
p.b +
|
||
", " +
|
||
p.opacity +
|
||
")"
|
||
);
|
||
gradient.addColorStop(
|
||
1,
|
||
"rgba(" +
|
||
p.r +
|
||
", " +
|
||
p.g +
|
||
", " +
|
||
p.b +
|
||
", 0)"
|
||
);
|
||
ctx.fillStyle = gradient;
|
||
ctx.arc(
|
||
p.location.x,
|
||
p.location.y,
|
||
p.radius,
|
||
Math.PI * 2,
|
||
false
|
||
);
|
||
ctx.fill();
|
||
|
||
//lets move the particles
|
||
p.remaining_life--;
|
||
p.radius -= 0.2;
|
||
p.location.x += p.speed.x;
|
||
p.location.y += p.speed.y;
|
||
|
||
//regenerate particles
|
||
if (p.remaining_life < 0 || p.radius < 0) {
|
||
//a brand new particle replacing the dead one
|
||
particles[i] = new particle();
|
||
}
|
||
}
|
||
requestAnimationFrame(draw);
|
||
};
|
||
|
||
draw();
|
||
game.haveFun.blinkLoop = draw;
|
||
game.haveFun.blinkStop = function () {
|
||
game.haveFun.list.blink.running = false;
|
||
};
|
||
}
|
||
},
|
||
star: function () {
|
||
if (game.haveFun.list.star.running) return;
|
||
game.haveFun.list.star.running = true;
|
||
if (game.haveFun.starLoop) {
|
||
game.haveFun.starLoop();
|
||
} else {
|
||
//******************************************************
|
||
// Yet Another Particle Engine
|
||
var cos = Math.cos,
|
||
sin = Math.sin,
|
||
sqrt = Math.sqrt,
|
||
abs = Math.abs,
|
||
atan2 = Math.atan2,
|
||
log = Math.log,
|
||
random = Math.random,
|
||
PI = Math.PI,
|
||
sqr = function (v) {
|
||
return v * v;
|
||
},
|
||
particles = [],
|
||
drawScale = 1,
|
||
emitters = [],
|
||
forces = [],
|
||
collidedMass = 0,
|
||
maxParticles = 100,
|
||
emissionRate = 1,
|
||
minParticleSize = 2;
|
||
|
||
//-------------------------------------------------------
|
||
// Vectors, and not the kind you put stuff in
|
||
var Vector = function (x, y, z) {
|
||
this.x = x || 0;
|
||
this.y = y || 0;
|
||
this.z = z || 0;
|
||
};
|
||
Vector.prototype = {
|
||
add: function (vector) {
|
||
this.x += vector.x;
|
||
this.y += vector.y;
|
||
this.z += vector.z;
|
||
return this;
|
||
},
|
||
subtract: function (vector) {
|
||
this.x -= vector.x;
|
||
this.y -= vector.y;
|
||
this.z -= vector.z;
|
||
return this;
|
||
},
|
||
multiply: function (another) {
|
||
this.x /= another.x;
|
||
this.y /= another.y;
|
||
this.z /= another.z;
|
||
return this;
|
||
},
|
||
divide: function (another) {
|
||
this.x /= another.x;
|
||
this.y /= another.y;
|
||
this.z /= another.z;
|
||
return this;
|
||
},
|
||
scale: function (factor) {
|
||
this.x *= factor;
|
||
this.y *= factor;
|
||
this.z *= factor;
|
||
return this;
|
||
},
|
||
magnitude: function () {
|
||
return sqrt(sqr(this.x + this.y));
|
||
},
|
||
distance: function (another) {
|
||
return abs(
|
||
sqrt(
|
||
sqr(this.x - another.x) +
|
||
sqr(this.y - another.y)
|
||
)
|
||
);
|
||
},
|
||
angle: function (angle, magnitude) {
|
||
if (angle && magnitude)
|
||
return Vector.fromAngle(angle, magnitude);
|
||
return atan2(this.y, this.x);
|
||
},
|
||
clone: function () {
|
||
return new Vector(this.x, this.y, this.z);
|
||
},
|
||
equals: function (another) {
|
||
return (
|
||
this.x === another.x &&
|
||
this.y === another.y &&
|
||
this.z === another.z
|
||
);
|
||
},
|
||
random: function (r) {
|
||
this.x += random() * r * 2 - r;
|
||
this.y += random() * r * 2 - r;
|
||
return this;
|
||
},
|
||
};
|
||
Vector.fromAngle = function (angle, magnitude) {
|
||
return new Vector(
|
||
magnitude * cos(angle),
|
||
magnitude * sin(angle),
|
||
magnitude * sin(angle)
|
||
);
|
||
};
|
||
|
||
//******************************************************
|
||
// A thing with mass, position, and velocity - like your mom
|
||
var Particle = function (pt, vc, ac, mass) {
|
||
this.pos = pt || new Vector(0, 0);
|
||
this.vc = vc || new Vector(0, 0);
|
||
this.ac = ac || new Vector(0, 0);
|
||
this.mass = mass || 1;
|
||
this.alive = true;
|
||
};
|
||
Particle.prototype.move = function () {
|
||
this.vc.add(this.ac);
|
||
this.pos.add(this.vc);
|
||
};
|
||
Particle.prototype.reactToForces = function (fields) {
|
||
var totalAccelerationX = 0;
|
||
var totalAccelerationY = 0;
|
||
|
||
for (var i = 0; i < fields.length; i++) {
|
||
var field = fields[i];
|
||
var vectorX = field.pos.x - this.pos.x;
|
||
var vectorY = field.pos.y - this.pos.y;
|
||
var distance = this.pos.distance(field.pos);
|
||
if (distance < 1) field.grow(this);
|
||
if (distance < 100) this.doubleSize = true;
|
||
var force = G(
|
||
this.forceBetween(field, distance)
|
||
);
|
||
totalAccelerationX += vectorX * force;
|
||
totalAccelerationY += vectorY * force;
|
||
}
|
||
this.ac = new Vector(
|
||
totalAccelerationX,
|
||
totalAccelerationY
|
||
);
|
||
|
||
totalAccelerationX = 0;
|
||
totalAccelerationY = 0;
|
||
for (var i = 0; i < particles.length; i++) {
|
||
var field = particles[i];
|
||
if (field === this || !field.alive) continue;
|
||
var vectorX = field.pos.x - this.pos.x;
|
||
var vectorY = field.pos.y - this.pos.y;
|
||
var distance = this.pos.distance(field.pos);
|
||
if (distance < 1) {
|
||
if (this.mass >= field.mass) {
|
||
var massRatio = this.mass / field.mass;
|
||
if (
|
||
particles.length <= maxParticles &&
|
||
this.mass > 40
|
||
) {
|
||
this.alive = false;
|
||
this.nova = true;
|
||
collidedMass += this.mass;
|
||
} else this.grow(field);
|
||
} else this.alive = false;
|
||
}
|
||
if (this.alive) {
|
||
var force = G(
|
||
this.forceBetween(field, distance)
|
||
);
|
||
totalAccelerationX += vectorX * G(force);
|
||
totalAccelerationY += vectorY * G(force);
|
||
}
|
||
}
|
||
|
||
var travelDist = this.pos.distance(
|
||
this.lastPos ? this.lastPos : this.pos
|
||
);
|
||
this.velocity =
|
||
travelDist -
|
||
(this.lastDistance
|
||
? this.lastDistance
|
||
: travelDist);
|
||
this.lastDistance = travelDist;
|
||
this.lastPos = this.pos.clone();
|
||
|
||
this.ac.add(
|
||
new Vector(
|
||
totalAccelerationX,
|
||
totalAccelerationY
|
||
)
|
||
);
|
||
this.lastPos = this.pos.clone();
|
||
// if(this.mass > 20) {
|
||
// var chance = 1 / (this.mass - 20);
|
||
// if(Math.random()>chance) {
|
||
// this.supernova = true;
|
||
// this.supernovaDur = 10;
|
||
// this.alive = false;
|
||
// if(particles.length <= maxParticles) collidedMass += this.mass;
|
||
// delete this.size;
|
||
// }
|
||
// }
|
||
};
|
||
Particle.prototype.grow = function (another) {
|
||
this.mass += another.mass;
|
||
this.nova = true;
|
||
another.alive = false;
|
||
delete this.size;
|
||
};
|
||
Particle.prototype.breakApart = function (
|
||
minMass,
|
||
maxParts
|
||
) {
|
||
if (!minMass) minMass = 1;
|
||
if (!maxParts) maxParts = 2;
|
||
var remainingMass = this.mass;
|
||
var num = 0;
|
||
while (remainingMass > 0) {
|
||
var np = new Particle(
|
||
this.pos.clone().random(this.mass),
|
||
new Vector(0, 0)
|
||
);
|
||
np.mass =
|
||
1 + Math.random() * (remainingMass - 1);
|
||
if (num >= maxParts - 1)
|
||
np.mass = remainingMass;
|
||
np.mass = np.mass < minMass ? minMass : np.mass;
|
||
remainingMass -= np.mass;
|
||
num++;
|
||
}
|
||
this.nova = true;
|
||
delete this.size;
|
||
this.alive = false;
|
||
};
|
||
Particle.prototype.forceBetween = function (
|
||
another,
|
||
distance
|
||
) {
|
||
var distance = distance
|
||
? distance
|
||
: this.pos.distance(another.pos);
|
||
return (this.mass * another.mass) / sqr(distance);
|
||
};
|
||
|
||
//******************************************************
|
||
//This certainly doesn't *sub*mit to particles, that's for sure
|
||
var ParticleEmitter = function (pos, vc, ang) {
|
||
// to do config options for emitter - random, static, show emitter, emitter color, etc
|
||
this.pos = pos;
|
||
this.vc = vc;
|
||
this.ang = ang || 0.09;
|
||
this.color = "#999";
|
||
};
|
||
ParticleEmitter.prototype.emit = function () {
|
||
var angle =
|
||
this.vc.angle() +
|
||
this.ang -
|
||
Math.random() * this.ang * 2;
|
||
var magnitude = this.vc.magnitude();
|
||
var position = this.pos.clone();
|
||
position.add(
|
||
new Vector(
|
||
~~(Math.random() * 100 - 50) * drawScale,
|
||
~~(Math.random() * 100 - 50) * drawScale
|
||
)
|
||
);
|
||
var velocity = Vector.fromAngle(angle, magnitude);
|
||
return new Particle(position, velocity);
|
||
};
|
||
|
||
//******************************************************
|
||
// Use it, Luke
|
||
// to do collapse functionality into particle
|
||
var Force = function (pos, m) {
|
||
this.pos = pos;
|
||
this.mass = m || 100;
|
||
};
|
||
Force.prototype.grow = function (another) {
|
||
this.mass += another.mass;
|
||
this.burp = true;
|
||
another.alive = false;
|
||
};
|
||
|
||
var G = function (data) {
|
||
return 0.00674 * data;
|
||
};
|
||
|
||
//******************************************************
|
||
var canvas = document.createElement("canvas");
|
||
canvas.classList.add("fun");
|
||
ui.window.appendChild(canvas);
|
||
var ctx = canvas.getContext("2d");
|
||
canvas.width = ui.window.offsetWidth;
|
||
canvas.height = ui.window.offsetHeight;
|
||
var canvasWidth = canvas.width;
|
||
var canvasHeight = canvas.height;
|
||
lib.onresize.push(function () {
|
||
canvas.width = ui.window.offsetWidth;
|
||
canvas.height = ui.window.offsetHeight;
|
||
canvasWidth = canvas.width;
|
||
canvasHeight = canvas.height;
|
||
});
|
||
|
||
var renderToCanvas = function (
|
||
width,
|
||
height,
|
||
renderFunction
|
||
) {
|
||
var buffer = document.createElement("canvas");
|
||
buffer.width = width;
|
||
buffer.height = height;
|
||
renderFunction(buffer.getContext("2d"));
|
||
return buffer;
|
||
};
|
||
|
||
maxParticles = 500;
|
||
emissionRate = 1;
|
||
drawScale = 1.3;
|
||
minParticleSize = 2;
|
||
emitters = [
|
||
//br
|
||
new ParticleEmitter(
|
||
new Vector(
|
||
(canvasWidth / 2) * drawScale + 400,
|
||
(canvasHeight / 2) * drawScale
|
||
),
|
||
Vector.fromAngle(2, 5),
|
||
1
|
||
),
|
||
// // bl
|
||
// new ParticleEmitter(
|
||
// new Vector(
|
||
// canvasWidth / 2 * drawScale - 400,
|
||
// canvasHeight / 2 * drawScale + 400
|
||
// ),
|
||
// Vector.fromAngle(1.5, 1),
|
||
// 1
|
||
// ),
|
||
// tl
|
||
new ParticleEmitter(
|
||
new Vector(
|
||
(canvasWidth / 2) * drawScale - 400,
|
||
(canvasHeight / 2) * drawScale
|
||
),
|
||
Vector.fromAngle(5, 5),
|
||
1
|
||
),
|
||
// // tr
|
||
// new ParticleEmitter(
|
||
// new Vector(
|
||
// canvasWidth / 2 * drawScale + 400,
|
||
// canvasHeight / 2 * drawScale - 400
|
||
// ),
|
||
// Vector.fromAngle(4.5, 1),
|
||
// 1
|
||
// )
|
||
];
|
||
forces = [
|
||
new Force(
|
||
new Vector(
|
||
(canvasWidth / 2) * drawScale,
|
||
(canvasHeight / 2) * drawScale
|
||
),
|
||
1800
|
||
),
|
||
];
|
||
|
||
var loop = function () {
|
||
if (!game.haveFun.list.star.running) {
|
||
canvas.width = ui.window.offsetWidth;
|
||
canvas.height = ui.window.offsetHeight;
|
||
return;
|
||
}
|
||
clear();
|
||
update();
|
||
draw();
|
||
queue();
|
||
};
|
||
game.haveFun.starLoop = loop;
|
||
game.haveFun.starStop = function () {
|
||
game.haveFun.list.star.running = false;
|
||
};
|
||
|
||
var clear = function () {
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
};
|
||
|
||
var ctr = 0;
|
||
var c = [
|
||
"rgba(255,255,255,",
|
||
"rgba(0,150,255,",
|
||
"rgba(255,255,128,",
|
||
"rgba(255,255,255,",
|
||
];
|
||
var rndc = function () {
|
||
return c[~~(Math.random() * c.length - 1)];
|
||
};
|
||
var c2 = "rgba(255,64,32,";
|
||
var addNewParticles = function () {
|
||
var _emit = function () {
|
||
var ret = 0;
|
||
for (var i = 0; i < emitters.length; i++) {
|
||
for (var j = 0; j < emissionRate; j++) {
|
||
var p = emitters[i].emit();
|
||
p.color =
|
||
ctr % 10 === 0
|
||
? Math.random() * 5 <= 1
|
||
? c2
|
||
: rndc()
|
||
: rndc();
|
||
p.mass = ~~(Math.random() * 5);
|
||
particles.push(p);
|
||
ret += p.mass;
|
||
ctr++;
|
||
}
|
||
}
|
||
return ret;
|
||
};
|
||
if (collidedMass !== 0) {
|
||
while (collidedMass !== 0) {
|
||
collidedMass -= _emit();
|
||
collidedMass =
|
||
collidedMass < 0 ? 0 : collidedMass;
|
||
}
|
||
}
|
||
if (particles.length > maxParticles) return;
|
||
_emit();
|
||
};
|
||
|
||
var CLIPOFFSCREEN = 1,
|
||
BUFFEROFFSCREEN = 2,
|
||
LOOPSCREEN = 3;
|
||
|
||
var isPositionAliveAndAdjust = function (
|
||
particle,
|
||
check
|
||
) {
|
||
return true;
|
||
// var pos = particle.pos;
|
||
// if(!check) check = BUFFEROFFSCREEN;
|
||
// if(check === CLIPOFFSCREEN) {
|
||
// return !(!particle.alive ||
|
||
// pos.x < 0 ||
|
||
// (pos.x / drawScale) > boundsX ||
|
||
// pos.y < 0 ||
|
||
// (pos.y / drawScale) > boundsY);
|
||
// } else if(check === BUFFEROFFSCREEN) {
|
||
// return !(!particle.alive ||
|
||
// pos.x < -boundsX * drawScale ||
|
||
// pos.x > 2 * boundsX * drawScale ||
|
||
// pos.y < -boundsY * drawScale ||
|
||
// pos.y > 2 * boundsY * drawScale);
|
||
// } else if(check === LOOPSCREEN) {
|
||
// if (pos.x < 0) pos.x = boundsX * drawScale;
|
||
// if ((pos.x / drawScale) > boundsX) pos.x = 0;
|
||
// if (pos.y < 0) pos.y = boundsY * drawScale;
|
||
// if ((pos.y / drawScale) > boundsY) pos.y = 0;
|
||
// return true;
|
||
// }
|
||
};
|
||
|
||
var plotParticles = function (boundsX, boundsY) {
|
||
var currentParticles = [];
|
||
for (var i = 0; i < particles.length; i++) {
|
||
var particle = particles[i];
|
||
particle.reactToForces(forces);
|
||
if (!isPositionAliveAndAdjust(particle))
|
||
continue;
|
||
particle.move();
|
||
currentParticles.push(particle);
|
||
}
|
||
};
|
||
|
||
var offscreenCache = {};
|
||
var renderParticle = function (p) {
|
||
var position = p.pos;
|
||
if (!p.size) p.size = Math.floor(p.mass / 100);
|
||
|
||
if (!p.opacity) p.opacity = 0.05;
|
||
if (p.velocity > 0) {
|
||
if (p.opacity <= 0.18) p.opacity += 0.04;
|
||
}
|
||
if (p.opacity > 0.08) p.opacity -= 0.02;
|
||
|
||
var actualSize = p.size / drawScale;
|
||
actualSize =
|
||
actualSize < minParticleSize
|
||
? minParticleSize
|
||
: actualSize;
|
||
if (p.mass > 8) actualSize *= 2;
|
||
if (p.nova) {
|
||
actualSize *= 4;
|
||
p.nova = false;
|
||
}
|
||
if (p.doubleSize) {
|
||
p.doubleSize = false;
|
||
actualSize *= 2;
|
||
}
|
||
// if(p.supernova) {
|
||
// actualSize *= 6;
|
||
// opacity = 0.15;
|
||
// p.supernovaDur = p.supernovaDur - 1;
|
||
// if(p.supernovaDur === 0)
|
||
// p.supernova = false;
|
||
// }
|
||
var cacheKey =
|
||
actualSize + "_" + p.opacity + "_" + p.color;
|
||
var cacheValue = offscreenCache[cacheKey];
|
||
if (!cacheValue) {
|
||
cacheValue = renderToCanvas(
|
||
actualSize * 32,
|
||
actualSize * 32,
|
||
function (ofsContext) {
|
||
var opacity = p.opacity;
|
||
var fills = [
|
||
{
|
||
size: actualSize / 2,
|
||
opacity: 1,
|
||
},
|
||
{
|
||
size: actualSize,
|
||
opacity: opacity,
|
||
},
|
||
{
|
||
size: actualSize * 2,
|
||
opacity: opacity / 2,
|
||
},
|
||
{
|
||
size: actualSize * 4,
|
||
opacity: opacity / 3,
|
||
},
|
||
{
|
||
size: actualSize * 8,
|
||
opacity: opacity / 5,
|
||
},
|
||
{
|
||
size: actualSize * 16,
|
||
opacity: opacity / 16,
|
||
},
|
||
];
|
||
ofsContext.beginPath();
|
||
for (var f in fills) {
|
||
f = fills[f];
|
||
ofsContext.fillStyle =
|
||
p.color + f.opacity + ")";
|
||
ofsContext.arc(
|
||
actualSize * 16,
|
||
actualSize * 16,
|
||
f.size,
|
||
0,
|
||
Math.PI * 2,
|
||
true
|
||
);
|
||
ofsContext.fill();
|
||
}
|
||
ofsContext.closePath();
|
||
}
|
||
);
|
||
offscreenCache[cacheKey] = cacheValue;
|
||
}
|
||
var posX = p.pos.x / drawScale;
|
||
var posY = p.pos.y / drawScale;
|
||
ctx.drawImage(cacheValue, posX, posY);
|
||
};
|
||
|
||
var fills = [
|
||
{ size: 15, opacity: 1 },
|
||
{ size: 25, opacity: 0.3 },
|
||
{ size: 50, opacity: 0.1 },
|
||
];
|
||
|
||
var renderScene = function (ofsContext) {
|
||
for (var i = 0; i < forces.length; i++) {
|
||
var p = forces[i];
|
||
var position = p.pos;
|
||
var opacity = 1;
|
||
|
||
ofsContext.beginPath();
|
||
for (var f in fills) {
|
||
f = fills[f];
|
||
var o = p.burp === true ? 1 : f.opacity;
|
||
p.burp = false;
|
||
// ofsContext.fillStyle = 'rgba(255,255,255,' + o + ')';
|
||
// ofsContext.arc(position.x / drawScale,
|
||
// position.y / drawScale,
|
||
// f.size / drawScale, 0, Math.PI*2, true);
|
||
// ofsContext.fill();
|
||
}
|
||
ofsContext.closePath();
|
||
}
|
||
|
||
for (var i = 0; i < particles.length; i++) {
|
||
var p = particles[i];
|
||
renderParticle(p);
|
||
}
|
||
};
|
||
|
||
var draw = function () {
|
||
renderScene(ctx);
|
||
};
|
||
|
||
var update = function () {
|
||
addNewParticles();
|
||
plotParticles(canvas.width, canvas.height);
|
||
};
|
||
|
||
var queue = function () {
|
||
window.requestAnimationFrame(loop);
|
||
};
|
||
|
||
loop();
|
||
}
|
||
},
|
||
snow: function () {
|
||
game.haveFun.list.snow.running = true;
|
||
if (game.haveFun.snowStart) {
|
||
game.haveFun.snowStart();
|
||
} else {
|
||
/*
|
||
* 自由下雪 snowFall
|
||
* author:xuanfeng
|
||
* time: 2014-01-11
|
||
*/
|
||
// 控制下雪
|
||
var canvas;
|
||
var snowFall = function (snow) {
|
||
// 可配置属性
|
||
snow = snow || {};
|
||
this.maxFlake = snow.maxFlake || 200; //最多片数
|
||
this.flakeSize = snow.flakeSize || 10; //雪花形状
|
||
this.fallSpeed = snow.fallSpeed || 2; //坠落速度
|
||
this.status = 0; //0-初始化、1-开始下雪、2-停止下雪、3-暂停下雪、4-继续下雪
|
||
};
|
||
|
||
// 兼容写法
|
||
var requestAnimationFrame =
|
||
window.requestAnimationFrame ||
|
||
window.mozRequestAnimationFrame ||
|
||
window.webkitRequestAnimationFrame ||
|
||
window.msRequestAnimationFrame ||
|
||
window.oRequestAnimationFrame ||
|
||
function (callback) {
|
||
setTimeout(callback, 1000 / 60);
|
||
};
|
||
var cancelAnimationFrame =
|
||
window.cancelAnimationFrame ||
|
||
window.mozCancelAnimationFrame ||
|
||
window.webkitCancelAnimationFrame ||
|
||
window.msCancelAnimationFrame ||
|
||
window.oCancelAnimationFrame;
|
||
|
||
// 开始下雪
|
||
snowFall.prototype.start = function () {
|
||
if (this.status == 1 || this.status == 4) {
|
||
// 已经在下雪则不作处理
|
||
return false;
|
||
}
|
||
this.status = 1;
|
||
|
||
// 创建画布
|
||
snowCanvas.apply(this);
|
||
// 创建雪花形状
|
||
createFlakes.apply(this);
|
||
// 画雪
|
||
drawSnow.apply(this);
|
||
};
|
||
|
||
// 停止下雪
|
||
snowFall.prototype.stop = function () {
|
||
if (
|
||
this.status == 2 ||
|
||
this.status == 0 ||
|
||
!this.canvas
|
||
) {
|
||
return false;
|
||
}
|
||
// 停止动画循环
|
||
this.pause();
|
||
this.status = 2;
|
||
// 删除画布
|
||
this.canvas.parentNode.removeChild(this.canvas);
|
||
this.canvas = null;
|
||
};
|
||
|
||
// 暂停下雪
|
||
snowFall.prototype.pause = function () {
|
||
if (this.status == 3) {
|
||
return false;
|
||
}
|
||
this.status = 3;
|
||
cancelAnimationFrame(this.loop);
|
||
};
|
||
// 继续下雪
|
||
snowFall.prototype.resume = function () {
|
||
if (this.status == 3 && this.canvas) {
|
||
this.status = 4;
|
||
// 动画的计时控制
|
||
var that = this;
|
||
this.loop = requestAnimationFrame(function () {
|
||
drawSnow.apply(that);
|
||
});
|
||
}
|
||
};
|
||
|
||
// 创建画布
|
||
var snowCanvas = function () {
|
||
// 添加Dom结点
|
||
var snowcanvas = document.createElement("canvas");
|
||
snowcanvas.classList.add("fun");
|
||
snowcanvas.id = "snowfall";
|
||
ui.window.appendChild(snowcanvas);
|
||
canvas = snowcanvas;
|
||
this.canvas = snowcanvas;
|
||
this.ctx = snowcanvas.getContext("2d");
|
||
// 窗口大小改变的处理
|
||
lib.onresize.push(function () {
|
||
snowcanvas.width = ui.window.offsetWidth;
|
||
snowcanvas.height = ui.window.offsetHeight;
|
||
});
|
||
snowcanvas.width = ui.window.offsetWidth;
|
||
snowcanvas.height = ui.window.offsetHeight;
|
||
};
|
||
|
||
// 雪运动对象
|
||
var flakeMove = function (
|
||
canvasWidth,
|
||
canvasHeight,
|
||
flakeSize,
|
||
fallSpeed
|
||
) {
|
||
this.x = Math.floor(Math.random() * canvasWidth); //x坐标
|
||
this.y = Math.floor(Math.random() * canvasHeight); //y坐标
|
||
this.size = Math.random() * flakeSize + 2; //形状
|
||
this.maxSize = flakeSize; //最大形状
|
||
this.speed = Math.random() * 1 + fallSpeed; //坠落速度
|
||
this.fallSpeed = fallSpeed; //坠落速度
|
||
this.velY = this.speed; //Y方向速度
|
||
this.velX = 0; //X方向速度
|
||
this.stepSize = Math.random() / 30; //步长
|
||
this.step = 0; //步数
|
||
};
|
||
|
||
flakeMove.prototype.update = function () {
|
||
var x = this.x,
|
||
y = this.y;
|
||
|
||
// 左右摆动(余弦)
|
||
this.velX *= 0.98;
|
||
if (this.velY <= this.speed) {
|
||
this.velY = this.speed;
|
||
}
|
||
this.velX +=
|
||
Math.cos((this.step += 0.05)) * this.stepSize;
|
||
|
||
this.y += this.velY;
|
||
this.x += this.velX;
|
||
// 飞出边界的处理
|
||
if (
|
||
this.x >= canvas.width ||
|
||
this.x <= 0 ||
|
||
this.y >= canvas.height ||
|
||
this.y <= 0
|
||
) {
|
||
this.reset(canvas.width, canvas.height);
|
||
}
|
||
};
|
||
|
||
// 飞出边界-放置最顶端继续坠落
|
||
flakeMove.prototype.reset = function (width, height) {
|
||
this.x = Math.floor(Math.random() * width);
|
||
this.y = 0;
|
||
this.size = Math.random() * snow.flakeSize + 2;
|
||
this.speed = Math.random() * 1 + snow.fallSpeed;
|
||
this.velY = this.speed;
|
||
this.velX = 0;
|
||
};
|
||
|
||
// 渲染雪花-随机形状
|
||
flakeMove.prototype.render = function (ctx) {
|
||
var snowFlake = ctx.createRadialGradient(
|
||
this.x,
|
||
this.y,
|
||
0,
|
||
this.x,
|
||
this.y,
|
||
this.size
|
||
);
|
||
snowFlake.addColorStop(
|
||
0,
|
||
"rgba(255, 255, 255, 0.9)"
|
||
);
|
||
snowFlake.addColorStop(
|
||
0.5,
|
||
"rgba(255, 255, 255, 0.5)"
|
||
);
|
||
snowFlake.addColorStop(1, "rgba(255, 255, 255, 0)");
|
||
ctx.save();
|
||
ctx.fillStyle = snowFlake;
|
||
ctx.beginPath();
|
||
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.restore();
|
||
};
|
||
|
||
// 创建雪花-定义形状
|
||
var createFlakes = function () {
|
||
var maxFlake = this.maxFlake,
|
||
flakes = (this.flakes = []),
|
||
canvas = this.canvas;
|
||
for (var i = 0; i < 200; i++) {
|
||
flakes.push(
|
||
new flakeMove(
|
||
canvas.width,
|
||
canvas.height,
|
||
this.flakeSize,
|
||
this.fallSpeed
|
||
)
|
||
);
|
||
}
|
||
};
|
||
|
||
// 画雪
|
||
var drawSnow = function () {
|
||
var maxFlake = this.maxFlake,
|
||
flakes = this.flakes;
|
||
var ctx = this.ctx,
|
||
canvas = this.canvas,
|
||
that = this;
|
||
// 清空雪花
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
for (var e = 0; e < maxFlake; e++) {
|
||
flakes[e].update();
|
||
flakes[e].render(ctx);
|
||
}
|
||
// 一帧一帧的画
|
||
this.loop = requestAnimationFrame(function () {
|
||
drawSnow.apply(that);
|
||
});
|
||
};
|
||
|
||
// 调用及控制方法
|
||
var snow = new snowFall();
|
||
game.haveFun.snowStart = function () {
|
||
snow.start();
|
||
};
|
||
game.haveFun.snowStop = function () {
|
||
game.haveFun.list.snow.running = false;
|
||
snow.stop();
|
||
};
|
||
game.haveFun.snowSize = function () {
|
||
if (game.haveFun.list.snow.size == "large") {
|
||
game.haveFun.list.snow.size = "small";
|
||
snow.maxFlake = 80;
|
||
snow.flakeSize = 3;
|
||
snow.fallSpeed = 1;
|
||
if (this && this.innerHTML) {
|
||
this.innerHTML = "大雪";
|
||
}
|
||
game.saveConfig("coinSnowSize", true);
|
||
} else {
|
||
game.haveFun.list.snow.size = "large";
|
||
snow.maxFlake = 200;
|
||
snow.flakeSize = 10;
|
||
snow.fallSpeed = 2;
|
||
if (this && this.innerHTML) {
|
||
this.innerHTML = "小雪";
|
||
}
|
||
game.saveConfig("coinSnowSize", false);
|
||
}
|
||
};
|
||
if (lib.config.coinSnowSize) {
|
||
game.haveFun.snowSize();
|
||
}
|
||
snow.start();
|
||
}
|
||
},
|
||
firework: function () {
|
||
if (game.haveFun.list.firework.running) return;
|
||
game.haveFun.list.firework.running = true;
|
||
if (game.haveFun.fireworkLoop) {
|
||
game.haveFun.fireworkLoop();
|
||
} else {
|
||
// when animating on canvas, it is best to use requestAnimationFrame instead of setTimeout or setInterval
|
||
// not supported in all browsers though and sometimes needs a prefix, so we need a shim
|
||
var requestAnimFrame = (function () {
|
||
return (
|
||
window.requestAnimationFrame ||
|
||
window.webkitRequestAnimationFrame ||
|
||
window.mozRequestAnimationFrame ||
|
||
function (callback) {
|
||
window.setTimeout(callback, 1000 / 60);
|
||
}
|
||
);
|
||
})();
|
||
|
||
// now we will setup our basic variables for the demo
|
||
var canvas = document.createElement("canvas"),
|
||
ctx = canvas.getContext("2d"),
|
||
// full screen dimensions
|
||
cw = ui.window.offsetWidth,
|
||
ch = ui.window.offsetHeight,
|
||
// firework collection
|
||
fireworks = [],
|
||
// particle collection
|
||
particles = [],
|
||
// starting hue
|
||
hue = 120,
|
||
// when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks
|
||
limiterTotal = 5,
|
||
limiterTick = 0,
|
||
// this will time the auto launches of fireworks, one launch per 80 loop ticks
|
||
timerTotal = 80,
|
||
timerTick = 0,
|
||
mousedown = false,
|
||
// mouse x coordinate,
|
||
mx,
|
||
// mouse y coordinate
|
||
my;
|
||
|
||
// set canvas dimensions
|
||
canvas.width = cw;
|
||
canvas.height = ch;
|
||
ui.window.appendChild(canvas);
|
||
canvas.classList.add("fun");
|
||
lib.onresize.push(function () {
|
||
cw = ui.window.offsetWidth;
|
||
ch = ui.window.offsetHeight;
|
||
canvas.width = cw;
|
||
canvas.height = ch;
|
||
});
|
||
|
||
// now we are going to setup our function placeholders for the entire demo
|
||
|
||
// get a random number within a range
|
||
var random = function (min, max) {
|
||
return Math.random() * (max - min) + min;
|
||
};
|
||
|
||
// calculate the distance between two points
|
||
var calculateDistance = function (p1x, p1y, p2x, p2y) {
|
||
var xDistance = p1x - p2x,
|
||
yDistance = p1y - p2y;
|
||
return Math.sqrt(
|
||
Math.pow(xDistance, 2) + Math.pow(yDistance, 2)
|
||
);
|
||
};
|
||
|
||
// create firework
|
||
var Firework = function (sx, sy, tx, ty) {
|
||
// actual coordinates
|
||
this.x = sx;
|
||
this.y = sy;
|
||
// starting coordinates
|
||
this.sx = sx;
|
||
this.sy = sy;
|
||
// target coordinates
|
||
this.tx = tx;
|
||
this.ty = ty;
|
||
// distance from starting point to target
|
||
this.distanceToTarget = calculateDistance(
|
||
sx,
|
||
sy,
|
||
tx,
|
||
ty
|
||
);
|
||
this.distanceTraveled = 0;
|
||
// track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails
|
||
this.coordinates = [];
|
||
this.coordinateCount = 3;
|
||
// populate initial coordinate collection with the current coordinates
|
||
while (this.coordinateCount--) {
|
||
this.coordinates.push([this.x, this.y]);
|
||
}
|
||
this.angle = Math.atan2(ty - sy, tx - sx);
|
||
this.speed = 2;
|
||
this.acceleration = 1.05;
|
||
this.brightness = random(50, 70);
|
||
// circle target indicator radius
|
||
this.targetRadius = 1;
|
||
};
|
||
|
||
// update firework
|
||
Firework.prototype.update = function (index) {
|
||
// remove last item in coordinates array
|
||
this.coordinates.pop();
|
||
// add current coordinates to the start of the array
|
||
this.coordinates.unshift([this.x, this.y]);
|
||
|
||
// cycle the circle target indicator radius
|
||
if (this.targetRadius < 8) {
|
||
this.targetRadius += 0.3;
|
||
} else {
|
||
this.targetRadius = 1;
|
||
}
|
||
|
||
// speed up the firework
|
||
this.speed *= this.acceleration;
|
||
|
||
// get the current velocities based on angle and speed
|
||
var vx = Math.cos(this.angle) * this.speed,
|
||
vy = Math.sin(this.angle) * this.speed;
|
||
// how far will the firework have traveled with velocities applied?
|
||
this.distanceTraveled = calculateDistance(
|
||
this.sx,
|
||
this.sy,
|
||
this.x + vx,
|
||
this.y + vy
|
||
);
|
||
|
||
// if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
|
||
if (
|
||
this.distanceTraveled >= this.distanceToTarget
|
||
) {
|
||
createParticles(this.tx, this.ty);
|
||
// remove the firework, use the index passed into the update function to determine which to remove
|
||
fireworks.splice(index, 1);
|
||
} else {
|
||
// target not reached, keep traveling
|
||
this.x += vx;
|
||
this.y += vy;
|
||
}
|
||
};
|
||
|
||
// draw firework
|
||
Firework.prototype.draw = function () {
|
||
ctx.beginPath();
|
||
// move to the last tracked coordinate in the set, then draw a line to the current x and y
|
||
ctx.moveTo(
|
||
this.coordinates[
|
||
this.coordinates.length - 1
|
||
][0],
|
||
this.coordinates[this.coordinates.length - 1][1]
|
||
);
|
||
ctx.lineTo(this.x, this.y);
|
||
ctx.strokeStyle =
|
||
"hsl(" +
|
||
hue +
|
||
", 100%, " +
|
||
this.brightness +
|
||
"%)";
|
||
ctx.stroke();
|
||
|
||
ctx.beginPath();
|
||
// draw the target for this firework with a pulsing circle
|
||
ctx.arc(
|
||
this.tx,
|
||
this.ty,
|
||
this.targetRadius,
|
||
0,
|
||
Math.PI * 2
|
||
);
|
||
ctx.stroke();
|
||
};
|
||
|
||
// create particle
|
||
var Particle = function (x, y) {
|
||
this.x = x;
|
||
this.y = y;
|
||
// track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
|
||
this.coordinates = [];
|
||
this.coordinateCount = 5;
|
||
while (this.coordinateCount--) {
|
||
this.coordinates.push([this.x, this.y]);
|
||
}
|
||
// set a random angle in all possible directions, in radians
|
||
this.angle = random(0, Math.PI * 2);
|
||
this.speed = random(1, 10);
|
||
// friction will slow the particle down
|
||
this.friction = 0.95;
|
||
// gravity will be applied and pull the particle down
|
||
this.gravity = 1;
|
||
// set the hue to a random number +-20 of the overall hue variable
|
||
this.hue = random(hue - 20, hue + 20);
|
||
this.brightness = random(50, 80);
|
||
this.alpha = 1;
|
||
// set how fast the particle fades out
|
||
this.decay = random(0.015, 0.03);
|
||
};
|
||
|
||
// update particle
|
||
Particle.prototype.update = function (index) {
|
||
// remove last item in coordinates array
|
||
this.coordinates.pop();
|
||
// add current coordinates to the start of the array
|
||
this.coordinates.unshift([this.x, this.y]);
|
||
// slow down the particle
|
||
this.speed *= this.friction;
|
||
// apply velocity
|
||
this.x += Math.cos(this.angle) * this.speed;
|
||
this.y +=
|
||
Math.sin(this.angle) * this.speed +
|
||
this.gravity;
|
||
// fade out the particle
|
||
this.alpha -= this.decay;
|
||
|
||
// remove the particle once the alpha is low enough, based on the passed in index
|
||
if (this.alpha <= this.decay) {
|
||
particles.splice(index, 1);
|
||
}
|
||
};
|
||
|
||
// draw particle
|
||
Particle.prototype.draw = function () {
|
||
ctx.beginPath();
|
||
// move to the last tracked coordinates in the set, then draw a line to the current x and y
|
||
ctx.moveTo(
|
||
this.coordinates[
|
||
this.coordinates.length - 1
|
||
][0],
|
||
this.coordinates[this.coordinates.length - 1][1]
|
||
);
|
||
ctx.lineTo(this.x, this.y);
|
||
ctx.strokeStyle =
|
||
"hsla(" +
|
||
this.hue +
|
||
", 100%, " +
|
||
this.brightness +
|
||
"%, " +
|
||
this.alpha +
|
||
")";
|
||
ctx.stroke();
|
||
};
|
||
|
||
// create particle group/explosion
|
||
var createParticles = function (x, y) {
|
||
// increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
|
||
var particleCount = 30;
|
||
while (particleCount--) {
|
||
particles.push(new Particle(x, y));
|
||
}
|
||
};
|
||
|
||
// main demo loop
|
||
var loop = function () {
|
||
// if(lib.config.coin_free_playpackconfig&&!_status.imchoosing){
|
||
// canvas.style.display='none';
|
||
// }
|
||
// else{
|
||
// canvas.style.display='';
|
||
// }
|
||
// this function will run endlessly with requestAnimationFrame
|
||
if (!game.haveFun.list.firework.running) {
|
||
canvas.width = cw;
|
||
canvas.height = ch;
|
||
return;
|
||
} else {
|
||
requestAnimFrame(loop);
|
||
}
|
||
|
||
// increase the hue to get different colored fireworks over time
|
||
hue += 0.5;
|
||
|
||
// normally, clearRect() would be used to clear the canvas
|
||
// we want to create a trailing effect though
|
||
// setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
|
||
ctx.globalCompositeOperation = "destination-out";
|
||
// decrease the alpha property to create more prominent trails
|
||
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
|
||
ctx.fillRect(0, 0, cw, ch);
|
||
// change the composite operation back to our main mode
|
||
// lighter creates bright highlight points as the fireworks and particles overlap each other
|
||
ctx.globalCompositeOperation = "lighter";
|
||
|
||
// loop over each firework, draw it, update it
|
||
var i = fireworks.length;
|
||
while (i--) {
|
||
fireworks[i].draw();
|
||
fireworks[i].update(i);
|
||
}
|
||
|
||
// loop over each particle, draw it, update it
|
||
var i = particles.length;
|
||
while (i--) {
|
||
particles[i].draw();
|
||
particles[i].update(i);
|
||
}
|
||
|
||
// launch fireworks automatically to random coordinates, when the mouse isn't down
|
||
if (timerTick >= timerTotal) {
|
||
if (!mousedown) {
|
||
// start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen
|
||
fireworks.push(
|
||
new Firework(
|
||
cw / 2,
|
||
ch,
|
||
random(0, cw),
|
||
random(0, ch / 2)
|
||
)
|
||
);
|
||
timerTick = 0;
|
||
}
|
||
} else {
|
||
timerTick++;
|
||
}
|
||
|
||
// limit the rate at which fireworks get launched when mouse is down
|
||
if (limiterTick >= limiterTotal) {
|
||
if (mousedown) {
|
||
// start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
|
||
fireworks.push(
|
||
new Firework(cw / 2, ch, mx, my)
|
||
);
|
||
limiterTick = 0;
|
||
}
|
||
} else {
|
||
limiterTick++;
|
||
}
|
||
};
|
||
|
||
if (lib.config.touchscreen) {
|
||
ui.window.addEventListener(
|
||
"touchmove",
|
||
function (e) {
|
||
mx =
|
||
e.touches[0].clientX /
|
||
game.documentZoom -
|
||
canvas.offsetLeft;
|
||
my =
|
||
e.touches[0].clientY /
|
||
game.documentZoom -
|
||
canvas.offsetTop;
|
||
}
|
||
);
|
||
ui.window.addEventListener(
|
||
"touchstart",
|
||
function (e) {
|
||
mousedown = true;
|
||
}
|
||
);
|
||
ui.window.addEventListener(
|
||
"touchend",
|
||
function (e) {
|
||
mousedown = false;
|
||
}
|
||
);
|
||
} else {
|
||
// mouse event bindings
|
||
// update the mouse coordinates on mousemove
|
||
ui.window.addEventListener(
|
||
"mousemove",
|
||
function (e) {
|
||
mx =
|
||
e.pageX / game.documentZoom -
|
||
canvas.offsetLeft;
|
||
my =
|
||
e.pageY / game.documentZoom -
|
||
canvas.offsetTop;
|
||
}
|
||
);
|
||
|
||
// toggle mousedown state and prevent canvas from being selected
|
||
ui.window.addEventListener(
|
||
"mousedown",
|
||
function (e) {
|
||
e.preventDefault();
|
||
mousedown = true;
|
||
}
|
||
);
|
||
|
||
ui.window.addEventListener("mouseup", function (e) {
|
||
e.preventDefault();
|
||
mousedown = false;
|
||
});
|
||
}
|
||
|
||
// once the window loads, we are ready for some fireworks!
|
||
game.haveFun.fireworkLoop = loop;
|
||
(game.haveFun.fireworkStop = function () {
|
||
game.haveFun.list.firework.running = false;
|
||
}),
|
||
loop();
|
||
}
|
||
},
|
||
},
|
||
},
|
||
help: {
|
||
富甲天下:
|
||
"<ul><li>每完成一次对局,可获得一定数量的金币" +
|
||
"<li>战斗胜利可额外获得20金币,每杀死一个敌人可获得10金币(托管无效)" +
|
||
"<li>使用的武将越强,获得的金币数越少" +
|
||
"<li>执行以下操作时,将扣除金币:<ul><li>作弊:20金币<li>换将卡:3金币<li>" +
|
||
"自由选将:10金币<li>手气卡:3金币<li>换人:10金币</ul>" +
|
||
"<li>金币可用于购买烟花等游戏特效(点击右上角的金币按钮)" +
|
||
"<li>修改金币:<br>game.changCoin" +
|
||
"<li>默认下雪:<br>game.haveFun.alwaysSnow",
|
||
},
|
||
};
|
||
});
|