簡體   English   中英

Splice (index,1) 正在從數組中刪除多個元素

[英]Splice (index,1) is removing more than one element from array

我正在 HTML Canvas 中制作一個簡單的游戲。 作為其中的一部分,我想在背景中制作流星,創造旅行的幻覺。 在星星到達 canvas 的末端后,我想將其移除。 每顆恆星都是 Star class 的一個實例,並且根據它的半徑,它具有不同的速度。 這就是問題開始的地方。 當對每顆恆星使用恆定速度時,它們會像應有的那樣一個接一個地消失。 當速度改變時,“超越”較慢恆星的恆星,當到達 canvas 的末端時,不僅會消失,還會移除在它們之前排列的所有恆星。 我嘗試了以下描述的許多解決方案:

let canvas = document.querySelector("canvas");
let c = canvas.getContext('2d');

星Class聲明:

class Star{
    constructor(x, y, radius, color, velocity){
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.velocity = velocity
    }

    draw(){
        c.globalCompositeOperation='destination-over'
        c.beginPath()
        c.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
        c.fillStyle = this.color;
        c.shadowColor= "white"
         c.shadowBlur=12
        c.fill();
        c.shadowBlur=0
    }
   
    update(){
        this.draw();
        this.y = this.y + this.radius/2;
    
    }
}

創建星星並將其添加到數組

let stars = [];
function createStar(){
    setInterval(()=>{
    //Create random radius and X position
    let randomRadius = Math.floor((Math.random()*5))
    let randomXPosition = Math.floor((Math.random()*780)+15)
    let velocity = 1;
    stars.push(new Star(randomXPosition, -randomRadius, randomRadius, "white",velocity));
    console.log("stars:"+ stars.length);
    },300)
}

下面我使用一個 function 調用自身來清除和刷新星圖。 我嘗試使用 forEach 方法循環遍歷 stars 數組,反向循環(如下面的示例),我嘗試將帶有拼接 function 的 if 語句放在單獨的 setTimeout(()=>{},0) 或 setTimeout(()=>{ },10)。 我嘗試使用類似的條件

(forEach 方法會移除星星,但活躍星星的數量不會保持不變。它會不斷緩慢增加)

function animate(){
  c.clearRect(0, 0, canvas.width, canvas.height);

   for(let i = stars.length-1; i>=0; i--){
        stars[i].update()
        if (stars[i].y > canvas.height +stars[i].radius ){
            stars.splice(stars[i], 1)
       }
    } 
requestAnimationFrame(animate);
}

animate();
createStar();

我嘗試使用以下條件:

if (stars[i].y > 5000 ){
    stars.splice(stars[i], 1)
}

但這不是應該如何解決的,因為星星的壽命要長 5000 像素,這讓游戲變得遲鈍。

只是為了清楚問題。 如果我每 300 毫秒生成 5 顆星並將其推入名為“stars”的數組中,我會得到例如 [star1,star2,star3,star4,star5]

假設star1 和star 2 的半徑很小,並且它們移動緩慢。 Star3 更大,因此它移動得更快,超過了前兩個。 當 star3 到達canvas.height + star[i].radius時,它會在 canvas 上方消失,但它也會使陣列中在 star3 之前的每顆恆星都消失(在這種情況下是 star1 和 star2)。

這是我在 stackoverflow 上的第一篇文章。 我提前為所有的輕描淡寫道歉。

HTML Canvas


<body>
    <div class="container">
        <button class="logOutButton">Log Out</button>
        <button class="topScores">Top 10</button>
        <header>
            <p class="hello">Hello <span id="spanName"></span></p>
            <p class="topScore">Your TOP score: <span id="score"></span></p>
        </header>

        <div class="gameTitle">
            <h2 class="title">Space Warrior</h2>
        </div>
        
        <canvas class="canvas" width="800" height="500"></canvas>
       
    </div>
    <script src="User.js"></script>
</body>

編輯我將stars.splice(stars[i], 1)更改為stars.splice(i, 1) - 不工作

我嘗試添加另一個像下面這樣的刪除數組,但數組stars慢慢變大(即使某些元素被刪除)

 var removeStar = [];
    // stars.forEach((star,starIndex)=>{
    let total = stars.length-1;
    
    for(let i = total; i>=0; i--){
        stars[i].update();

        if (stars[i].y > canvas.height + stars[i].radius){
            removeStar.push(i);
        }
    };

    for(let i = removeStar.length; i>0; i--){
        stars.splice(removeStar[i-1],1)
    }

您寫道: stars.splice(stars[i], 1)第一個參數應該是您要刪除的索引...只是索引stars.splice(i, 1) ..另一個問題是您在循環時更改了數組它,這是個壞主意。

看到這個非常相似的問題的答案: https://stackoverflow.com/a/65725703/3054380

在修復了上面提到的錯誤並添加了minVelocity和星限制條件之后(因為你添加了間隔並在星離開 canvas 時移除 - 我們需要限制以防間隔變快)......現在一切看起來都很好 - 下面的工作片段(添加了maxStars minVelocity

 let canvas = document.querySelector(".mycanvas"); let c = canvas.getContext('2d'); canvas.width = 300; canvas.height = 150; let maxStars = 60; let minVelocity = 0.5; let stars = []; class Star { constructor(x, y, radius, color, velocity) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.velocity = velocity } draw() { c.globalCompositeOperation = 'destination-over' c.beginPath() c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.fillStyle = this.color; c.shadowColor = "white" c.shadowBlur = 12 c.fill(); c.shadowBlur = 0 } update() { this.draw(); this.y = this.y + Math.max(minVelocity, this.velocity * this.radius / 2); } } function createStar() { if (stars.length < maxStars) { //Create random radius and X position let randomRadius = Math.floor((Math.random() * 5)); let randomXPosition = Math.floor((Math.random() * (canvas.width - 20)) + 10); let velocity = 1; stars.push(new Star(randomXPosition, -randomRadius, randomRadius, "white", velocity)); console.log("stars:" + stars.length); } } function animate() { c.clearRect(0, 0, canvas.width, canvas.height); for (let i = stars.length - 1; i >= 0; i--) { stars[i].update() if (stars[i].y > canvas.height) { stars.splice(i, 1) } } requestAnimationFrame(animate); } setInterval(createStar, 50); animate();
 .mycanvas { width: 300px; height: 150px; border: 1px solid #f00; }
 <body style="background-color:#000;color:#fff;"> <div class="container"> <canvas class="mycanvas"></canvas> </div> <script src="User.js"></script> </body>

我想我發現了導致您不斷擴展數組的問題。 它與您的拼接 function 無關,如他的回答中提到的 webdev-dan 錯誤地實施。

遵循這個邏輯

  • 半徑已使用Math.floor((Math.random()*5))設置。這意味着半徑可以為 0。
  • 在您的更新方法中,您根據this.y = this.y + this.radius/2中的radius增加y 所以這可能是用 0 改變 y。
  • if (stars[i].y > 5000 )中,您正在刪除y超過 5000 的值。

所以如果半徑是0y不會改變,星星永遠不會被移除。 您也無法從視覺上看到它們。

解決方案

您可以保證最小速度為 1. this.y += Math.max(1, this.radius/2)

PS:我不得不做相當多的重構來解決這個問題。 您正在以過於復雜的方式編寫代碼。 幾種類型的邏輯混合在一起。

您真的想將您的渲染邏輯與星星 object 的管理分開。

記住星星陣列也很困難,因為您可以從任何地方對其進行修改; 在 for 循環中,帶有異步代碼(間隔)。

這就是我在嘗試清理您的代碼時最終得到的結果: https://jsfiddle.net/5hk0vscg/1/希望它有用。 請注意,這不是完全清理,而是對您當前代碼的改進。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM