闲来无事,把three.js其中有一个例子改了一下,变成从一个中心点喷射出中文字的例子,下面直接贴代码好了
html:
<html lang="en">
<head>
<title>three.js canvas - text - sprites</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
a {
color: #0078ff;
}
@media screen and (max-width: 600px) {
html{
font-size:6px;
}
}
</style>
</head>
<body>
<div class="controls">
<input type="text" name="danmu" id="danmuInput"/>
<button onclick="sendText()">发射弹幕(send)</button>
</div>
<div class="clear" onclick="clearAll()">
清除(clear)
</div>
</body>
</html>
css只是表现层让他看起来稍微好看一点,所以不算是最重要的,除此之外写了一小部分便于在手机上浏览响应式css
css:
@media screen and (max-width: 600px) {
html{
font-size:6px;
}
}
html{
font-size:10px;
}
*{
margin:0;
padding:0;
box-sizing:border-box;
}
.controls{
width:40rem;
height:20rem;
border: 0.2rem solid #88f;
border-radius:0.5rem;
position:fixed;
bottom:1rem;
left:50%;
margin-left:-20rem;
background-color: rgba(155,155,255,0.1);
}
#danmuInput{
width:30rem;
font-size:2rem;
text-align:center;
background-color: rgba(155,155,255,0.6);
color:white;
height:3.8rem;
line-height:3.8rem;
margin:4rem 0 0 5rem;
border:0.1rem solid rgba(200,200,255,0.3);
}
#danmuInput:focus{
border:0.1rem solid rgba(200,200,255,0.9);
box-shadow:none;
outline:none;
box-shadow:0 0 0.2rem 0.1rem rgba(200,200,255,0.9);
}
.controls button{
position:absolute;
width:20rem;
height:4rem;
bottom:2rem;
left:50%;
margin-left:-10rem;
background-color: rgba(0,0,0,0);
color:white;
font-size:2rem;
text-shadow:0 0 5px #fff;
}
.controls button:hover{
cursor:pointer;
background-color: rgba(255,255,255,0.4);
color:#00f;
}
.clear{
width:12rem;
height:4rem;
background-color:rgba(255,177,255,0.1);
position:fixed;
top:2rem;
right:4rem;
font-size:2rem;
color:white;
font-weght:bold;
line-height:4rem;
text-align:center;
text-shadow:0 0 1rem rgba(255,177,255,0.6);
border-radius:0.4rem;
transition: all .3s;
}
.clear:hover{
cursor:pointer;
background-color:rgba(255,200,255,0.4);
line-height:3.8rem;
box-shadow:0 0 1rem 0.5rem rgba(255,200,255,0.2);
}
.clear:active{
cursor:pointer;
background-color:rgba(255,200,255,0.3);
line-height:4.2rem;
box-shadow:0 0 1rem 0.5rem rgba(255,200,255,0.2);
}
最关键的js部分:
前置js:
three.js
https://threejs.org/build/three.js
three.js的项目管理插件 方便
https://threejs.org/examples/js/renderers/Projector.js
tween渐变插件 有许多渐变函数可以用 用于制作动画
https://threejs.org/examples/js/libs/tween.min.js
three里面的信息搜集展示插件 可以显示帧数等性能信息
https://threejs.org/examples/js/libs/stats.min.js
画布渲染插件 ,因为three默认用的是webgl渲染有了这个插件可以用canvas原生2d模式渲染,添加canvas渲染器必备
https://threejs.org/examples/js/renderers/CanvasRenderer.js
var container, stats;
//首先最开始要生声明变量
var camera, scene, renderer, particle;
var mouseX = 0, mouseY = 0;
var text = "弹幕";
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
//初始化函数
init();
//动画函数 递归的方式调用
animate();
//初始化
function init() {
// 初始化canvas元素
container = document.createElement( 'div' );
document.body.appendChild( container );
//创建相机
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.z = 1000;
//创建场景
scene = new THREE.Scene();
var color = "red";
var material = new THREE.SpriteMaterial( {
map: new THREE.CanvasTexture( generateSprite(text,color) ),
blending: THREE.AdditiveBlending
} );
//生成100个并且每隔100ms出现一个
for ( var i = 0; i < 100; i++ ) {
particle = new THREE.Sprite( material );
initParticle( particle, i * 100 );
scene.add( particle );
}
//使用的渲染器是THREE的2Dcanvas渲染器而非webgl
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0x000040 );//设置清屏的颜色一般来说是背景的颜色这里设置了深蓝色
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//用于展现帧数等数据信息
stats = new Stats();
container.appendChild( stats.dom );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
//当网页窗口发生变化时改变canvas渲染部分的大小的函数
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//这个才是创建单个字符片段的函数
function generateSprite(text,style) {
var canvas = document.createElement( 'canvas' );
canvas.width = 300;
canvas.height = 300;
var context = canvas.getContext( '2d' );
context.beginPath();
context.font='50px Microsoft YaHei';
context.fillStyle = style;
context.fillText(text,0,50);
context.fill();
context.stroke();
return canvas;
}
//将例子中创建一个类似于星星的圆点的画布的函数换了名字
function generateTextSprite() {
//创建canvas画布
var canvas = document.createElement( 'canvas' );
canvas.width = 16;
canvas.height = 16;
//绘制
var context = canvas.getContext( '2d' );
//生成渐变圆点
var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 );
gradient.addColorStop( 0, 'rgba(255,255,255,1)' );
gradient.addColorStop( 0.2, 'rgba(0,255,255,1)' );
gradient.addColorStop( 0.4, 'rgba(0,0,64,1)' );
gradient.addColorStop( 1, 'rgba(0,0,0,1)' );
context.fillStyle = gradient;
context.fillRect( 0, 0, canvas.width, canvas.height );
return canvas;
}
function initParticle( particle, delay ) {
var particle = this instanceof THREE.Sprite ? this : particle;
var delay = delay !== undefined ? delay : 0;
particle.position.set( -500, 0, 0 );
particle.scale.x = particle.scale.y = 300 /*Math.random() * 32 + 16*/;
//用了线性函数插件
new TWEEN.Tween( particle )
.delay( delay )
.to( {}, 10000 )
.onComplete( initParticle )/*这是一个递归 用于持续产生 间隔10s钟*/
.start();
new TWEEN.Tween( particle.position )
.delay( delay )
.to( { x: Math.random() * 4000 - 2000, y: Math.random() * 1500 - 750, z: Math.random() * 4000 - 2000 }, 10000 )
.start();
new TWEEN.Tween( particle.scale )
.delay( delay )
.to( { x: 0.03, y: 0.03 }, 10000 )
.start();
}
//
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart( event ) {
if ( event.touches.length == 1 ) {
//event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) {
//event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
TWEEN.update();
camera.position.x += ( mouseX - camera.position.x ) * 0.05;
camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
function changeText(t){
if ( t != ''){
text = t;
}
console.log("nyan");
return text;
}
function changeTextAndShow(text,color){
//确定材料
//检测在场景中是否过多材料
if(scene.children.length>2000){return;};
var material = new THREE.SpriteMaterial( {
map: new THREE.CanvasTexture( generateSprite(text,color) ),
blending: THREE.AdditiveBlending
} );
//生成 并且加入到渲染环境中
for ( var i = 0; i < 10; i++ ) {
particle = new THREE.Sprite( material );
initParticle( particle, i * 10 );
scene.add( particle );
}
console.log("nyan");
}
function sendText(){
var texts = document.getElementById("danmuInput").value;
if(texts == '')return;
var color = getRandomColor();
changeTextAndShow(texts,color);
console.log("nyannnnn");
}
function getRandomColor(){
var color = "rgba(" + Math.floor(Math.random() * 155 + 100 ) + "," +
Math.floor(Math.random() * 155 + 100) + "," +
Math.floor(Math.random() * 155 +100) + "," +
(Math.random() * 0.5 + 0.5) + ")";
return color;
}
//个人恶趣味
setTimeout('changeTextAndShow("惊吓","yellow")',2000);
setTimeout('changeTextAndShow("nyancat","blue")',3000);
setTimeout('changeTextAndShow("QwQ","rgba(233,155,233,0.6)")',4000);
changeTextAndShow("惊吓","green");
function clearAll(){
scene.children.splice(0,scene.children.length);
}
//个人恶趣味 清空之后如果屏幕内没有弹幕则会过11秒加入10个弹幕,鉴于循环周期是10秒所以110秒之后有会有10秒的循环
function showTextWhenNoTextHere(){
if(scene.children.length>100){return;}
else{
console.log("show more");
changeTextAndShow("寂寞弹幕","yellow");
}
}
setInterval("showTextWhenNoTextHere()",11000);