threejs精灵和粒子系统

news/2025/1/31 9:04:45/

个人博客地址: https://cxx001.gitee.io

前面我们了解到了场景中的网格对象由几何体和材质组成,并且分别系统学习了它们。这节我们将学习一个特殊的网格对象-----粒子(精灵)。

了解粒子

一个粒子(新版叫精灵)是 一个二维平面(小方块) ,它总是面向摄像机。

<!-- chapter-07-01.html -->
<!DOCTYPE html>
<html>
<head><title>Particles</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);//var canvasRenderer = new THREE.CanvasRenderer();var canvasRenderer = new THREE.WebGLRenderer();canvasRenderer.setClearColor(new THREE.Color(0x000000, 1.0));canvasRenderer.setSize(window.innerWidth, window.innerHeight);camera.position.x = 0;camera.position.y = 0;camera.position.z = 150;document.getElementById("WebGL-output").appendChild(canvasRenderer.domElement);createSprites();render();function createSprites() {// 创建精灵材质var material = new THREE.SpriteMaterial();for (var x = -5; x < 5; x++) {for (var y = -5; y < 5; y++) {// 创建精灵,只需要指定材质var sprite = new THREE.Sprite(material);sprite.position.set(x * 10, y * 10, 0);scene.add(sprite);}}}function render() {stats.update();requestAnimationFrame(render);canvasRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>


大量粒子

如果要创建大量粒子,使用上面THREE.Sprite一个个创建那就太耗性能了。对于这种场景,我们要使用THREE.PointCloudMaterialTHREE.PointCloud来管理。

THREE.PointCloud构造函数接收两个属性:几何体和材质,和创建网格对象类似。材质用来给粒子着色或添加纹理,而几何体则用来指定粒子的位置,几何体每个顶点将会以粒子的形态展示出来。

THREE.PointCloudMaterial材质的属性:

<!-- chapter-07-02.html -->
<!DOCTYPE html>
<html>
<head><title>Particle Basic Material</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);camera.position.x = 20;camera.position.y = 0;camera.position.z = 150;document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var cloud;var controls = new function () {this.size = 4;this.transparent = true;this.opacity = 0.6;this.vertexColors = true;this.color = 0xffffff;this.sizeAttenuation = true;this.rotateSystem = true;this.redraw = function () {if (scene.getObjectByName("particles")) {scene.remove(scene.getObjectByName("particles"));}createParticles(controls.size, controls.transparent, controls.opacity, controls.vertexColors, controls.sizeAttenuation, controls.color);};};var gui = new dat.GUI();gui.add(controls, 'size', 0, 10).onChange(controls.redraw);gui.add(controls, 'transparent').onChange(controls.redraw);gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw);gui.add(controls, 'vertexColors').onChange(controls.redraw);gui.addColor(controls, 'color').onChange(controls.redraw);gui.add(controls, 'sizeAttenuation').onChange(controls.redraw);gui.add(controls, 'rotateSystem');controls.redraw();render();// 使用THREE.PointCloud创建大量粒子function createParticles(size, transparent, opacity, vertexColors, sizeAttenuation, color) {// 创建点云材质var material = new THREE.PointCloudMaterial({size: size,transparent: transparent,opacity: opacity,vertexColors: vertexColors,sizeAttenuation: sizeAttenuation,color: color});// 创建自定义几何体var geom = new THREE.Geometry();var range = 500;for (var i = 0; i < 15000; i++) {var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);geom.vertices.push(particle);var color = new THREE.Color(0x00ff00);color.setHSL(color.getHSL().h, color.getHSL().s, Math.random() * color.getHSL().l);geom.colors.push(color);}// 创建点云对象cloud = new THREE.PointCloud(geom, material);cloud.name = "particles";scene.add(cloud);}var step = 0;function render() {stats.update();if (controls.rotateSystem) {step += 0.01;cloud.rotation.x = step;cloud.rotation.z = step;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>

在这里插入图片描述


样式化粒子

默认粒子会渲染成小方块,下面来看看怎么改变粒子样式。

1. 使用HTML5画布样式化粒子

前面提到过,THREE.PointCloudMaterial的map属性可以为粒子加载纹理,以此来改变粒子样式(关于纹理后续会详细介绍,这里只需关注使用)。首先我们看看把HTML5的画布转换为纹理来作为粒子的纹理运用。

<!-- chapter-07-03.html -->
<!DOCTYPE html>
<html>
<head><title>Particles - Canvas based texture - WebGL</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);camera.position.x = 20;camera.position.y = 0;camera.position.z = 150;document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);// 获取画布的纹理var getTexture = function () {var canvas = document.createElement('canvas');canvas.width = 32;canvas.height = 32;var ctx = canvas.getContext('2d');// the bodyctx.translate(-81, -84);ctx.fillStyle = "orange";ctx.beginPath();ctx.moveTo(83, 116);ctx.lineTo(83, 102);ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);ctx.lineTo(111, 116);ctx.lineTo(106.333, 111.333);ctx.lineTo(101.666, 116);ctx.lineTo(97, 111.333);ctx.lineTo(92.333, 116);ctx.lineTo(87.666, 111.333);ctx.lineTo(83, 116);ctx.fill();// the eyesctx.fillStyle = "white";ctx.beginPath();ctx.moveTo(91, 96);ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);ctx.moveTo(103, 96);ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);ctx.fill();// the pupilsctx.fillStyle = "blue";ctx.beginPath();ctx.arc(101, 102, 2, 0, Math.PI * 2, true);ctx.fill();ctx.beginPath();ctx.arc(89, 102, 2, 0, Math.PI * 2, true);ctx.fill();var texture = new THREE.Texture(canvas);texture.needsUpdate = true;return texture;};var cloud;var controls = new function () {this.size = 15;this.transparent = true;this.opacity = 0.6;this.color = 0xffffff;this.rotateSystem = true;this.sizeAttenuation = true;this.redraw = function () {if (scene.getObjectByName("pointcloud")) {scene.remove(scene.getObjectByName("pointcloud"));}createPointCloud(controls.size, controls.transparent, controls.opacity, controls.sizeAttenuation, controls.color);};};var gui = new dat.GUI();gui.add(controls, 'size', 0, 20).onChange(controls.redraw);gui.add(controls, 'transparent').onChange(controls.redraw);gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw);gui.addColor(controls, 'color').onChange(controls.redraw);gui.add(controls, 'sizeAttenuation').onChange(controls.redraw);gui.add(controls, 'rotateSystem');controls.redraw();render();function createPointCloud(size, transparent, opacity, sizeAttenuation, color) {var geom = new THREE.Geometry();var material = new THREE.PointCloudMaterial({size: size,transparent: transparent,opacity: opacity,map: getTexture(),  // 使用外部纹理sizeAttenuation: sizeAttenuation,color: color});var range = 500;for (var i = 0; i < 5000; i++) {var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);geom.vertices.push(particle);}cloud = new THREE.PointCloud(geom, material);cloud.name = 'pointcloud';// 渲染之前所以粒子按z轴排序,解决部分粒子交叠问题,但是注意会影响性能。cloud.sortParticles = true;// 开启后摄像机可见范围外的粒子不会渲染,必要时,使用可以提高性能和帧率。cloud.FrustumCulled = true;scene.add(cloud);}var step = 0;function render() {stats.update();if (controls.rotateSystem) {step += 0.01;cloud.rotation.x = step;cloud.rotation.z = step;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>

2. 使用纹理样式化粒子

前面使用HTML5画布输出纹理还是显得麻烦,我们还有一种更直接的方式,你可以使用THREE.ImageUtils.loadTexture()函数将图像加载为THREE.Texture,然后赋值给材质的map属性。

注意图片应该是正方形的,并且尺寸最好是2的幂,背景选择黑色(能够更正确地融合)。

<!-- chapter-07-04.html -->
<!DOCTYPE html>
<html>
<head><title>Particles - Rainy scene</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);camera.position.x = 20;camera.position.y = 40;camera.position.z = 110;camera.lookAt(new THREE.Vector3(20, 30, 0));document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var cloud;var controls = new function () {this.size = 3;this.transparent = true;this.opacity = 0.6;this.color = 0xffffff;this.sizeAttenuation = true;this.redraw = function () {scene.remove(scene.getObjectByName("particles1"));scene.remove(scene.getObjectByName("particles2"));createPointCloud(controls.size, controls.transparent, controls.opacity, controls.sizeAttenuation, controls.color);};};var gui = new dat.GUI();gui.add(controls, 'size', 0, 20).onChange(controls.redraw);gui.add(controls, 'transparent').onChange(controls.redraw);gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw);gui.addColor(controls, 'color').onChange(controls.redraw);gui.add(controls, 'sizeAttenuation').onChange(controls.redraw);controls.redraw();render();function createPointCloud(size, transparent, opacity, sizeAttenuation, color) {// 加载本地图片作为粒子纹理var texture = THREE.ImageUtils.loadTexture("../assets/textures/particles/raindrop-3.png");var geom = new THREE.Geometry();var material = new THREE.ParticleBasicMaterial({size: size,transparent: transparent,opacity: opacity,map: texture,blending: THREE.AdditiveBlending,sizeAttenuation: sizeAttenuation,color: color});var range = 40;for (var i = 0; i < 1500; i++) {var particle = new THREE.Vector3(Math.random() * range - range / 2,Math.random() * range * 1.5,Math.random() * range - range / 2);particle.velocityY = 0.1 + Math.random() / 5;particle.velocityX = (Math.random() - 0.5) / 3;geom.vertices.push(particle);}cloud = new THREE.ParticleSystem(geom, material);cloud.sortParticles = true;scene.add(cloud);}function render() {stats.update();// 模拟下雨效果var vertices = cloud.geometry.vertices;vertices.forEach(function (v) {v.y = v.y - (v.velocityY);v.x = v.x - (v.velocityX);if (v.y <= 0) v.y = 60;if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;});requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>

在这里插入图片描述


使用精灵贴图

精灵贴图是很多小精灵图片打包在一张图片上,一次加载这张大图后,使用时通过纹理的偏移来选取需要的小图片。

这个示例展示了创建两个场景使用不同摄像机(游戏里场景和UI界面就可以这样使用)

<!-- chapter-07-05.html -->
<!DOCTYPE html>
<html>
<head><title>Particles - Sprites</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();// 透视相机场景和正交相机场景var scene = new THREE.Scene();var sceneOrtho = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 250);var cameraOrtho = new THREE.OrthographicCamera(0, window.innerWidth, window.innerHeight, 0, -10, 10);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);camera.position.x = 0;camera.position.y = 0;camera.position.z = 50;document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);// 球体var material = new THREE.MeshNormalMaterial();var geom = new THREE.SphereGeometry(15, 20, 20);var mesh = new THREE.Mesh(geom, material);scene.add(mesh);// 获取精灵贴图纹理var getTexture = function () {var texture = new THREE.ImageUtils.loadTexture("../assets/textures/particles/sprite-sheet.png");return texture;};var controls = new function () {this.size = 150;this.sprite = 0;this.transparent = true;this.opacity = 0.6;this.color = 0xffffff;this.rotateSystem = true;this.redraw = function () {sceneOrtho.children.forEach(function (child) {if (child instanceof THREE.Sprite) sceneOrtho.remove(child);});createSprite(controls.size, controls.transparent, controls.opacity, controls.color, controls.sprite);};};var gui = new dat.GUI();gui.add(controls, 'sprite', 0, 4).step(1).onChange(controls.redraw);gui.add(controls, 'size', 0, 120).onChange(controls.redraw);gui.add(controls, 'transparent').onChange(controls.redraw);gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw);gui.addColor(controls, 'color').onChange(controls.redraw);controls.redraw();render();function createSprite(size, transparent, opacity, color, spriteNumber) {var spriteMaterial = new THREE.SpriteMaterial({opacity: opacity,color: color,transparent: transparent,map: getTexture()});// 通过map的offset/repeat选择精灵贴图里的精灵图片,范围0~1spriteMaterial.map.offset = new THREE.Vector2(0.2 * spriteNumber, 0);spriteMaterial.map.repeat = new THREE.Vector2(1 / 5, 1);var sprite = new THREE.Sprite(spriteMaterial);sprite.scale.set(size, size, size);sprite.position.set(100, 50, -10);sprite.velocityX = 5;   // 精灵x轴移动速度因子sceneOrtho.add(sprite);  // 小人精灵添加到正交场景中}var step = 0;function render() {stats.update();// 透视相机y轴运动camera.position.y = Math.sin(step += 0.01) * 20;// 正交相机里的精灵x轴左右移动sceneOrtho.children.forEach(function (e) {if (e instanceof THREE.Sprite) {// move the sprite along the bottome.position.x = e.position.x + e.velocityX;if (e.position.x > window.innerWidth) {e.velocityX = -5;e.material.map.offset.set(1 / 5 * (controls.sprite % 4), 0);}if (e.position.x < 0) {e.velocityX = 5;}}});requestAnimationFrame(render);webGLRenderer.render(scene, camera);webGLRenderer.autoClear = false; // 关闭自动清理,不然在sceneOrtho render时会清理scene的,那么就会导致看不到scene里的球体了webGLRenderer.render(sceneOrtho, cameraOrtho);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>


从高级几何体创建THREE.PointCloud

前面我们知道了THREE.PointCloud是基于几何体的顶点来渲染每个粒子的。前面我们都是使用的自定义顶点,其实也可以直接用高级几何体创建点云。

示例:使用上节的环状扭结几何体创建粒子

<!-- chapter-07-06.html -->
<!DOCTYPE html>
<html>
<head><title>3D Torusknot</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = -30;camera.position.y = 40;camera.position.z = 50;camera.lookAt(new THREE.Vector3(10, 0, 0));document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var knot;var controls = new function () {this.radius = 13;this.tube = 1.7;this.radialSegments = 156;this.tubularSegments = 12;this.p = 5;this.q = 4;this.heightScale = 3.5;this.asParticles = false;this.rotate = false;this.redraw = function () {if (knot) scene.remove(knot);// 创建环状扭结几何体var geom = new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q), controls.heightScale);if (controls.asParticles) {// 创建点云对象knot = createPointCloud(geom);} else {// 创建网格对象knot = createMesh(geom);}scene.add(knot);};};var gui = new dat.GUI();gui.add(controls, 'radius', 0, 40).onChange(controls.redraw);gui.add(controls, 'tube', 0, 40).onChange(controls.redraw);gui.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw);gui.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw);gui.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw);gui.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw);gui.add(controls, 'heightScale', 0, 5).onChange(controls.redraw);gui.add(controls, 'asParticles').onChange(controls.redraw);gui.add(controls, 'rotate').onChange(controls.redraw);controls.redraw();render();// 获取当前画布的纹理信息function generateSprite() {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);var texture = new THREE.Texture(canvas);texture.needsUpdate = true;return texture;}function createPointCloud(geom) {var material = new THREE.PointCloudMaterial({color: 0xffffff,size: 3,transparent: true,blending: THREE.AdditiveBlending,map: generateSprite()  // 使用HTML5画布的纹理});var cloud = new THREE.PointCloud(geom, material);cloud.sortParticles = true;return cloud;}function createMesh(geom) {var meshMaterial = new THREE.MeshNormalMaterial({});meshMaterial.side = THREE.DoubleSide;var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]);return mesh;}function render() {stats.update();if (controls.rotate) {knot.rotation.y += 0.01;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.domElement.style.position = 'absolute';stats.domElement.style.left = '0px';stats.domElement.style.top = '0px';document.getElementById("Stats-output").appendChild(stats.domElement);return stats;}}window.onload = init;
</script>
</body>
</html>


http://www.ppmy.cn/news/653010.html

相关文章

MoveIt教程 - Move Group (C++接口)

MoveIt教程 - Move Group (C++接口) 环境: ubuntu20.04 ros noetic 克隆项目: git clone https://github.com/ros-planning/moveit.git git clone https://github.com/ros-planning/moveit_visual_tools.git git clone https://github.com/ros-planning/moveit_tutori…

雷霆战机源代码c语言,C++实现雷霆战机可视化小游戏

用C++和easyx实现简单的雷霆战机小游戏 之前在网上看了许多关于c++或者是其他语言实现雷霆战机的帖子,大多不完整,或者是要付费才能阅读,现将源码展示如下,仅作学习交流之用。 基本原理 基本思路 代码如下 注意:运行代码所需环境为c++11或更高,代码中所涉及的图片、背景音…

雷霆战机单机老版本_雷霆战机单机版

雷霆战机单机版是一款弹幕射击游戏&#xff0c;此类游戏&#xff0c;相信玩家都在红白机上体验过&#xff0c;玩家将会操控一加航天战斗机在外太空中与敌人战斗&#xff0c;雷霆战机有无尽与闯关两种模式&#xff0c;欢迎更多玩家下载雷霆战机免费版加入体验一波。 雷霆战机单机…

War Thunder for Mac(战争雷霆)中文版

战争雷霆Mac版是Mac平台上一款非常受欢迎的军事类游戏&#xff0c;战争雷霆War Thunder for Mac以二战历史为背景&#xff0c;提供陆战、空战两种游戏模式&#xff0c;玩家可以驾驶自己的飞机或者装甲车跟其他玩家战斗&#xff0c;场景华丽&#xff0c;战斗场面非常壮观&#x…

java雷霆战机项目收获_java实习项目_雷霆战机

实习项目:雷霆战机 1、项目需求分析&#xff1a; 游戏状态state&#xff1a; start准备状态 running运行状态 pause暂停状态 gameover游戏结束状态 英雄机:一个&#xff0c;走步行为(即两张图片的切换) 与鼠标一起移动的行为&#xff0c;鼠标位于英雄机的中心位置。 射击行为:子…

战争雷霆怎么设置中文?war thunder简体中文

战争雷霆Mac版是Mac平台上一款非常受欢迎的军事类游戏&#xff0c;战争雷霆War Thunder for Mac以二战历史为背景&#xff0c;提供陆战、空战两种游戏模式&#xff0c;玩家可以驾驶自己的飞机或者装甲车跟其他玩家战斗&#xff0c;场景华丽&#xff0c;战斗场面非常壮观&#x…

c语言课设雷霆战机编程,C语言写的雷霆战机

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include #include #include #pragma comment(lib,"winmm.lib") DWORD t1, t2;//计算时间的变量 DWORD tt1, tt2; //定义子弹的结构体,不占内存,只是类型而已 typedef struct Node {int …

密位测距离口诀_战争雷霆历史模式炮术教学 历史模式测距方法详解

方法五&#xff0c;最终奥义&#xff0c;用【密位】测距 OMG&#xff0c;这一段足以写成一本小册子。密位是坦克兵标准的测距法&#xff0c;熟练之后测距速度最快&#xff0c;最好用。 其根本原理&#xff0c;是根据物体【近大远小】&#xff0c;通过测量目标在瞄准镜上的大小&…