Files
Progetto-ingegneria-del-sof…/deliverables/Coverage/htmReport/ns-12/sources/source-1.html
T
2026-06-19 22:57:43 +02:00

516 lines
20 KiB
HTML

<!DOCTYPE html>
<html id="htmlId">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Coverage Report > FireParticleSystem</title>
<style type="text/css">
@import "../../css/coverage.css";
@import "../../css/idea.min.css";
</style>
<script type="text/javascript" src="../../js/highlight.min.js"></script>
<script type="text/javascript" src="../../js/highlightjs-line-numbers.min.js"></script>
</head>
<body>
<div class="content">
<div class="breadCrumbs">
Current scope: <a href="../../index.html">all classes</a>
<span class="separator">|</span>
<a href="../index.html">it.polimi.ingsw.gc14.View.GUI</a>
</div>
<h1>Coverage Summary for Class: FireParticleSystem (it.polimi.ingsw.gc14.View.GUI)</h1>
<table class="coverageStats">
<tr>
<th class="name">Class</th>
<th class="coverageStat
">
Method, %
</th>
<th class="coverageStat
">
Branch, %
</th>
<th class="coverageStat
">
Line, %
</th>
</tr>
<tr>
<td class="name">FireParticleSystem</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/5)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/29)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/49)
</span>
</td>
</tr>
<tr>
<td class="name">FireParticleSystem$1</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/2)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/2)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/4)
</span>
</td>
</tr>
<tr>
<td class="name">FireParticleSystem$Particle</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/7)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/40)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/69)
</span>
</td>
</tr>
<tr>
<td class="name"><strong>Total</strong></td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/14)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/71)
</span>
</td>
<td class="coverageStat">
<span class="percent">
0%
</span>
<span class="absValue">
(0/122)
</span>
</td>
</tr>
</table>
<br/>
<br/>
<pre>
<code class="sourceCode" id="sourceCode">&nbsp;package it.polimi.ingsw.gc14.View.GUI;
&nbsp;
&nbsp;import javafx.animation.AnimationTimer;
&nbsp;import javafx.scene.Scene;
&nbsp;import javafx.scene.layout.Pane;
&nbsp;import javafx.scene.paint.Color;
&nbsp;import javafx.scene.shape.Circle;
&nbsp;
&nbsp;import java.util.ArrayList;
&nbsp;import java.util.Iterator;
&nbsp;import java.util.List;
&nbsp;import java.util.Random;
&nbsp;
&nbsp;/**
&nbsp; * Ambient fire-particle effect rendered on a transparent overlay pane.
&nbsp; *
&nbsp; * &lt;p&gt;Three particle types float from the screen corners toward the center:
&nbsp; * &lt;ul&gt;
&nbsp; * &lt;li&gt;&lt;b&gt;embers&lt;/b&gt; (type 0) — slow, glowing orange circles with a soft halo.&lt;/li&gt;
&nbsp; * &lt;li&gt;&lt;b&gt;sparks&lt;/b&gt; (type 1) — fast, short-lived bright particles.&lt;/li&gt;
&nbsp; * &lt;li&gt;&lt;b&gt;dust&lt;/b&gt; (type 2) — large, translucent brown drifting circles.&lt;/li&gt;
&nbsp; * &lt;/ul&gt;
&nbsp; *
&nbsp; * &lt;p&gt;Call {@link #start()} after adding {@link #getPane()} to the scene graph
&nbsp; */
&nbsp;public class FireParticleSystem {
&nbsp;
&nbsp; /** Maximum number of live particles at any given time. */
&nbsp; private static final int MAX_PARTICLES = 30;
&nbsp; /** Minimum nanoseconds between particle spawn batches. */
&nbsp; private static final long SPAWN_INTERVAL_NS = 100_000_000L;
&nbsp; /** Minimum nanoseconds between rendered frames (30 fps cap). */
&nbsp; private static final long FRAME_INTERVAL_NS = 1_000_000_000L / 30;
&nbsp; /** Physics update steps applied per rendered frame (multiplies effective speed). */
&nbsp; private static final int STEPS_PER_FRAME = 3;
&nbsp;
&nbsp; /** Mouse-transparent overlay pane that hosts all particle nodes. */
&nbsp; private final Pane pane;
&nbsp; /** The scene whose dimensions are used to position and fade particles. */
&nbsp; private final Scene scene;
&nbsp; /** Currently live particles. */
<b class="nc">&nbsp; private final List&lt;Particle&gt; particles = new ArrayList&lt;&gt;();</b>
&nbsp; /** Shared random source for particle initialization and physics noise. */
<b class="nc">&nbsp; private final Random rnd = new Random();</b>
&nbsp; /** Timestamp (ns) of the last particle spawn batch. */
<b class="nc">&nbsp; private long lastSpawn = 0;</b>
&nbsp; /** Timestamp (ns) of the last rendered frame. */
<b class="nc">&nbsp; private long lastFrame = 0;</b>
&nbsp; /** {@code true} after the first tick pre-populates the particle pool. */
<b class="nc">&nbsp; private boolean warmedUp = false;</b>
&nbsp;
&nbsp; /**
&nbsp; * Creates the particle system bound to the given scene.
&nbsp; * The internal overlay pane is transparent and mouse-transparent.
&nbsp; *
&nbsp; * @param scene the scene whose dimensions are used for particle positioning and fading.
&nbsp; */
<b class="nc">&nbsp; public FireParticleSystem(Scene scene) {</b>
<b class="nc">&nbsp; this.scene = scene;</b>
<b class="nc">&nbsp; pane = new Pane();</b>
<b class="nc">&nbsp; pane.setMouseTransparent(true);</b>
<b class="nc">&nbsp; pane.setPickOnBounds(false);</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Returns the transparent overlay pane that holds all particle nodes.
&nbsp; *
&nbsp; * @return the mouse-transparent {@link Pane} overlay.
&nbsp; */
<b class="nc">&nbsp; public Pane getPane() { return pane; }</b>
&nbsp;
&nbsp; /** Starts the animation timer. */
&nbsp; public void start() {
<b class="nc">&nbsp; AnimationTimer timer = new AnimationTimer() {</b>
&nbsp; @Override
&nbsp; public void handle(long now) {
<b class="nc">&nbsp; if (now - lastFrame &lt; FRAME_INTERVAL_NS) return;</b>
<b class="nc">&nbsp; lastFrame = now;</b>
<b class="nc">&nbsp; tick(now);</b>
&nbsp; }
&nbsp; };
<b class="nc">&nbsp; timer.start();</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Advances the simulation by one frame: pre-warms on first call, spawns new particles,
&nbsp; * steps existing ones, removes dead ones, and updates their visual state.
&nbsp; *
&nbsp; * @param now the current timestamp in nanoseconds from the animation timer.
&nbsp; */
&nbsp; private void tick(long now) {
<b class="nc">&nbsp; double w = scene.getWidth();</b>
<b class="nc">&nbsp; double h = scene.getHeight();</b>
<b class="nc">&nbsp; if (w == 0 || h == 0) return;</b>
&nbsp;
<b class="nc">&nbsp; if (!warmedUp) {</b>
<b class="nc">&nbsp; warmedUp = true;</b>
<b class="nc">&nbsp; for (int i = 0; i &lt; MAX_PARTICLES; i++) {</b>
<b class="nc">&nbsp; Particle p = spawnParticle(w, h);</b>
<b class="nc">&nbsp; int advance = rnd.nextInt(800) + 100;</b>
<b class="nc">&nbsp; for (int f = 0; f &lt; advance; f++) p.update();</b>
<b class="nc">&nbsp; if (!p.isDead(w, h)) {</b>
<b class="nc">&nbsp; p.addTo(pane);</b>
<b class="nc">&nbsp; p.updateVisual(w, h);</b>
<b class="nc">&nbsp; particles.add(p);</b>
&nbsp; }
&nbsp; }
&nbsp; }
&nbsp;
<b class="nc">&nbsp; if (now - lastSpawn &gt; SPAWN_INTERVAL_NS &amp;&amp; particles.size() &lt; MAX_PARTICLES) {</b>
<b class="nc">&nbsp; lastSpawn = now;</b>
<b class="nc">&nbsp; int count = rnd.nextInt(2) + 1;</b>
<b class="nc">&nbsp; for (int i = 0; i &lt; count &amp;&amp; particles.size() &lt; MAX_PARTICLES; i++) {</b>
<b class="nc">&nbsp; Particle p = spawnParticle(w, h);</b>
<b class="nc">&nbsp; p.addTo(pane);</b>
<b class="nc">&nbsp; particles.add(p);</b>
&nbsp; }
&nbsp; }
&nbsp;
<b class="nc">&nbsp; Iterator&lt;Particle&gt; it = particles.iterator();</b>
<b class="nc">&nbsp; while (it.hasNext()) {</b>
<b class="nc">&nbsp; Particle p = it.next();</b>
<b class="nc">&nbsp; for (int s = 0; s &lt; STEPS_PER_FRAME; s++) p.update();</b>
<b class="nc">&nbsp; if (p.isDead(w, h)) {</b>
<b class="nc">&nbsp; p.removeFrom(pane);</b>
<b class="nc">&nbsp; it.remove();</b>
&nbsp; } else {
<b class="nc">&nbsp; p.updateVisual(w, h);</b>
&nbsp; }
&nbsp; }
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Creates a new particle starting near one of the four screen corners.
&nbsp; *
&nbsp; * @param w scene width in pixels.
&nbsp; * @param h scene height in pixels.
&nbsp; * @return the newly constructed {@link Particle}.
&nbsp; */
&nbsp; private Particle spawnParticle(double w, double h) {
<b class="nc">&nbsp; int corner = rnd.nextInt(4);</b>
<b class="nc">&nbsp; double margin = 0.12;</b>
&nbsp; double x, y;
<b class="nc">&nbsp; switch (corner) {</b>
<b class="nc">&nbsp; case 0 -&gt; { x = rnd.nextDouble() * w * margin; y = h - rnd.nextDouble() * h * margin; }</b>
<b class="nc">&nbsp; case 1 -&gt; { x = w - rnd.nextDouble() * w * margin; y = h - rnd.nextDouble() * h * margin; }</b>
<b class="nc">&nbsp; case 2 -&gt; { x = rnd.nextDouble() * w * margin; y = rnd.nextDouble() * h * margin; }</b>
<b class="nc">&nbsp; default -&gt; { x = w - rnd.nextDouble() * w * margin; y = rnd.nextDouble() * h * margin; }</b>
&nbsp; }
<b class="nc">&nbsp; return new Particle(x, y, w, h, corner, rnd);</b>
&nbsp; }
&nbsp;
&nbsp;
&nbsp; /**
&nbsp; * A single fire particle with position, velocity, wobble, and JavaFX visual nodes.
&nbsp; * Particles are typed: 0 = ember, 1 = spark, 2 = dust.
&nbsp; */
&nbsp; private static class Particle {
&nbsp;
&nbsp; /** Current X position in scene pixels. */
&nbsp; double x;
&nbsp; /** Current Y position in scene pixels. */
&nbsp; double y;
&nbsp; /** Horizontal velocity component. */
&nbsp; double vx;
&nbsp; /** Vertical velocity component. */
&nbsp; double vy;
&nbsp; /** Remaining life fraction (1.0 = full, 0.0 = dead); only decrements for sparks. */
&nbsp; double life;
&nbsp; /** Visual radius of the particle&#39;s core circle. */
&nbsp; final double size;
&nbsp; /** Current phase of the sinusoidal wobble. */
&nbsp; double wobblePhase;
&nbsp; /** Angular speed of the wobble oscillation. */
&nbsp; final double wobbleSpeed;
&nbsp; /** Amplitude factor of the wobble displacement. */
&nbsp; final double wobbleAmp;
&nbsp; /** Particle type: 0 = ember, 1 = spark, 2 = dust. */
&nbsp; final int type;
&nbsp; /** Shared random source used during physics updates. */
&nbsp; final Random rnd;
&nbsp;
&nbsp; /** Primary visible circle node. */
&nbsp; final Circle core;
&nbsp; /** Soft glow halo circle behind {@link #core}; non-null only for embers (type 0). */
&nbsp; final Circle glow;
&nbsp;
&nbsp; /**
&nbsp; * Initializes the particle at position ({@code x}, {@code y}) with velocity
&nbsp; * aimed roughly from the given {@code corner} toward the scene center.
&nbsp; *
&nbsp; * @param x spawn X coordinate.
&nbsp; * @param y spawn Y coordinate.
&nbsp; * @param w scene width (used to compute target direction).
&nbsp; * @param h scene height (used to compute target direction).
&nbsp; * @param corner spawn corner index: 0 = bottom-left, 1 = bottom-right, 2 = top-left, 3 = top-right.
&nbsp; * @param rnd shared random source.
&nbsp; */
<b class="nc">&nbsp; Particle(double x, double y, double w, double h, int corner, Random rnd) {</b>
<b class="nc">&nbsp; this.x = x;</b>
<b class="nc">&nbsp; this.y = y;</b>
<b class="nc">&nbsp; this.life = 1.0;</b>
<b class="nc">&nbsp; this.rnd = rnd;</b>
<b class="nc">&nbsp; this.type = weightedType(rnd);</b>
&nbsp;
<b class="nc">&nbsp; double targetX = (corner == 0 || corner == 2) ? w * 0.75 : w * 0.25;</b>
<b class="nc">&nbsp; double targetY = (corner == 0 || corner == 1) ? h * 0.25 : h * 0.75;</b>
<b class="nc">&nbsp; double baseAngle = Math.atan2(targetY - y, targetX - x);</b>
<b class="nc">&nbsp; double angle = baseAngle + (rnd.nextDouble() - 0.5) * (Math.PI / 3.5);</b>
&nbsp;
&nbsp; double speed;
<b class="nc">&nbsp; if (type == 0) {</b>
<b class="nc">&nbsp; speed = 0.5 + rnd.nextDouble() * 0.7;</b>
<b class="nc">&nbsp; size = rnd.nextDouble() * 3 + 2;</b>
<b class="nc">&nbsp; glow = new Circle(size * 2.2);</b>
<b class="nc">&nbsp; core = new Circle(size / 2);</b>
<b class="nc">&nbsp; } else if (type == 1) {</b>
<b class="nc">&nbsp; speed = 1.5 + rnd.nextDouble() * 2.0;</b>
<b class="nc">&nbsp; size = rnd.nextDouble() * 1.5 + 0.5;</b>
<b class="nc">&nbsp; glow = null;</b>
<b class="nc">&nbsp; core = new Circle(size / 2);</b>
&nbsp; } else {
<b class="nc">&nbsp; speed = 0.2 + rnd.nextDouble() * 0.35;</b>
<b class="nc">&nbsp; size = rnd.nextDouble() * 8 + 5;</b>
<b class="nc">&nbsp; glow = null;</b>
<b class="nc">&nbsp; core = new Circle(size);</b>
<b class="nc">&nbsp; core.setFill(Color.color(0.55, 0.38, 0.22));</b>
&nbsp; }
&nbsp;
<b class="nc">&nbsp; vx = Math.cos(angle) * speed;</b>
<b class="nc">&nbsp; vy = Math.sin(angle) * speed;</b>
<b class="nc">&nbsp; wobblePhase = rnd.nextDouble() * Math.PI * 2;</b>
<b class="nc">&nbsp; wobbleSpeed = 0.025 + rnd.nextDouble() * 0.04;</b>
<b class="nc">&nbsp; wobbleAmp = 0.1 + rnd.nextDouble() * 0.4;</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Returns a particle type weighted toward embers (55% ember, 23% spark, 22% dust).
&nbsp; *
&nbsp; * @param rnd the random source.
&nbsp; * @return particle type: 0, 1, or 2.
&nbsp; */
&nbsp; private static int weightedType(Random rnd) {
<b class="nc">&nbsp; double r = rnd.nextDouble();</b>
<b class="nc">&nbsp; if (r &lt; 0.55) return 0;</b>
<b class="nc">&nbsp; if (r &lt; 0.78) return 1;</b>
<b class="nc">&nbsp; return 2;</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Adds this particle&#39;s visual nodes to {@code pane} (glow first so core renders on top).
&nbsp; *
&nbsp; * @param pane the overlay pane to add nodes to.
&nbsp; */
&nbsp; void addTo(Pane pane) {
<b class="nc">&nbsp; if (glow != null) pane.getChildren().add(glow);</b>
<b class="nc">&nbsp; pane.getChildren().add(core);</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Removes this particle&#39;s visual nodes from {@code pane}.
&nbsp; *
&nbsp; * @param pane the overlay pane to remove nodes from.
&nbsp; */
&nbsp; void removeFrom(Pane pane) {
<b class="nc">&nbsp; pane.getChildren().remove(core);</b>
<b class="nc">&nbsp; if (glow != null) pane.getChildren().remove(glow);</b>
&nbsp; }
&nbsp;
&nbsp; /** Advances this particle by one physics step: applies wobble, moves, and decrements spark life. */
&nbsp; void update() {
<b class="nc">&nbsp; wobblePhase += wobbleSpeed;</b>
<b class="nc">&nbsp; vx += Math.sin(wobblePhase) * wobbleAmp * 0.05;</b>
<b class="nc">&nbsp; vy += Math.cos(wobblePhase) * wobbleAmp * 0.02;</b>
<b class="nc">&nbsp; x += vx;</b>
<b class="nc">&nbsp; y += vy;</b>
<b class="nc">&nbsp; if (type == 1) life -= 0.008 + rnd.nextDouble() * 0.006;</b>
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Returns {@code true} when this particle has left the scene bounds or, for sparks, its life reached zero.
&nbsp; *
&nbsp; * @param w scene width.
&nbsp; * @param h scene height.
&nbsp; * @return {@code true} if the particle should be removed.
&nbsp; */
&nbsp; boolean isDead(double w, double h) {
<b class="nc">&nbsp; double pad = size * 4;</b>
<b class="nc">&nbsp; return x &lt; -pad || x &gt; w + pad || y &lt; -pad || y &gt; h + pad</b>
&nbsp; || (type == 1 &amp;&amp; life &lt;= 0);
&nbsp; }
&nbsp;
&nbsp; /**
&nbsp; * Updates color, opacity, and translate position of this particle&#39;s visual nodes
&nbsp; * based on distance from scene edges and remaining life.
&nbsp; *
&nbsp; * @param w scene width.
&nbsp; * @param h scene height.
&nbsp; */
&nbsp; void updateVisual(double w, double h) {
<b class="nc">&nbsp; double edge = Math.min(w, h) * 0.05;</b>
<b class="nc">&nbsp; double fadeX = Math.min(x / edge, Math.min((w - x) / edge, 1.0));</b>
<b class="nc">&nbsp; double fadeY = Math.min(y / edge, Math.min((h - y) / edge, 1.0));</b>
<b class="nc">&nbsp; double posAlpha = Math.max(0, Math.min(fadeX, fadeY));</b>
<b class="nc">&nbsp; double lifeAlpha = (type == 1) ? Math.min(life * 2.0, 1.0) : 1.0;</b>
<b class="nc">&nbsp; double alpha = posAlpha * lifeAlpha;</b>
&nbsp;
<b class="nc">&nbsp; core.setTranslateX(x);</b>
<b class="nc">&nbsp; core.setTranslateY(y);</b>
&nbsp;
<b class="nc">&nbsp; if (type == 0) {</b>
<b class="nc">&nbsp; double dist = Math.sqrt((x - w/2) * (x - w/2) + (y - h/2) * (y - h/2));</b>
<b class="nc">&nbsp; double hotness = Math.max(0, 1.0 - dist / (Math.sqrt(w * w + h * h) * 0.4));</b>
<b class="nc">&nbsp; double g = 0.3 + hotness * 0.5;</b>
<b class="nc">&nbsp; core.setFill(Color.color(1.0, g, 0.0));</b>
<b class="nc">&nbsp; core.setOpacity(alpha * 0.88);</b>
<b class="nc">&nbsp; glow.setTranslateX(x);</b>
<b class="nc">&nbsp; glow.setTranslateY(y);</b>
<b class="nc">&nbsp; glow.setFill(Color.color(1.0, g * 0.35, 0.0));</b>
<b class="nc">&nbsp; glow.setOpacity(alpha * 0.10);</b>
<b class="nc">&nbsp; } else if (type == 1) {</b>
<b class="nc">&nbsp; double brightness = Math.min(life * 2.5, 1.0);</b>
<b class="nc">&nbsp; core.setFill(Color.color(1.0, brightness * 0.85 + 0.15, brightness * 0.15));</b>
<b class="nc">&nbsp; core.setOpacity(alpha);</b>
&nbsp; } else {
<b class="nc">&nbsp; core.setOpacity(alpha * 0.20);</b>
&nbsp; }
&nbsp; }
&nbsp; }
&nbsp;}
</code>
</pre>
</div>
<script type="text/javascript">
(function() {
var msie = false, msie9 = false;
/*@cc_on
msie = true;
@if (@_jscript_version >= 9)
msie9 = true;
@end
@*/
if (!msie || msie && msie9) {
hljs.highlightAll()
hljs.initLineNumbersOnLoad();
}
})();
</script>
<div class="footer">
<div style="float:right;">generated on 2026-06-19 22:53</div>
</div>
</body>
</html>