You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为四子棋(Connect Four)棋盘添加棋子下落动画的JS/CSS方案咨询

Awesome job getting your Connect Four game fully functional! Adding that satisfying drop animation will take it to the next level, and I’ve got a simple, jQuery-free solution that fits right into your existing code. We’ll use CSS transitions for the smooth fall and a tiny bit of JavaScript to handle the animation lifecycle.

Step 1: Add CSS for Animation & Positioning

First, drop these styles into your CSS file. They’ll handle the falling piece’s appearance and movement:

/* Make the table a relative container so we can position the falling piece inside it */
table {
  position: relative;
  /* Keep your existing table styles here */
}

/* Style the falling piece to match your game's hole size/shape */
.falling-piece {
  position: absolute;
  width: 50px; /* Match your .hole button width */
  height: 50px; /* Match your .hole button height */
  border-radius: 50%; /* Creates the classic Connect Four circle */
  pointer-events: none; /* Prevents the piece from blocking clicks mid-fall */
  transition: top 0.5s ease-in; /* Smooth, natural falling motion */
}

/* Optional: Tweak your hole styles if needed (ensure they're consistent) */
.hole {
  width: 50px;
  height: 50px;
  border: 1px solid #333;
  border-radius: 50%;
  background: #fff;
  position: relative; /* Helps with positioning context */
}

.droplocation {
  width: 50px;
  height: 50px;
  font-size: 24px;
}

Step 2: Create a Reusable Animation Helper Function

Add this JavaScript function to your script. It handles creating the falling piece, animating it from the top button to the target hole, and cleaning up once the animation finishes:

let isAnimating = false; // Prevent multiple clicks during animation

function animatePieceDrop(columnIndex, targetHoleId, pieceColor) {
  isAnimating = true;
  
  // Get elements we need for positioning
  const dropButton = document.getElementById(`Z${columnIndex}`);
  const targetHole = document.getElementById(targetHoleId);
  const table = document.querySelector('table');
  
  // Create the temporary falling piece
  const fallingPiece = document.createElement('div');
  fallingPiece.classList.add('falling-piece');
  fallingPiece.style.backgroundColor = pieceColor;
  
  // Calculate positions relative to the table
  const buttonPos = dropButton.getBoundingClientRect();
  const tablePos = table.getBoundingClientRect();
  const targetPos = targetHole.getBoundingClientRect();
  
  // Set the piece's starting position (right over the drop button)
  fallingPiece.style.left = `${buttonPos.left - tablePos.left}px`;
  fallingPiece.style.top = `${buttonPos.top - tablePos.top}px`;
  
  // Add the piece to the table
  table.appendChild(fallingPiece);
  
  // Force a reflow to trigger the transition (trick to make CSS transitions work)
  void fallingPiece.offsetWidth;
  
  // Set the final position (on top of the target hole)
  fallingPiece.style.top = `${targetPos.top - tablePos.top}px`;
  
  // When the animation ends: update the hole, clean up, and check for a win
  fallingPiece.addEventListener('transitionend', () => {
    targetHole.style.backgroundColor = pieceColor;
    table.removeChild(fallingPiece);
    
    // Check for win after the piece is in place
    if (pieceColor === '#f44256') {
      checkForRedWin();
    } else {
      checkForBlueWin();
    }
    
    isAnimating = false;
    // Don't forget to switch turns here if your code handles that!
  });
}

Step 3: Update Your Existing drop Functions

Now modify each of your 7 drop functions to use the animation instead of directly setting the background color. Here’s how your drop1() function will look (the others will follow the same pattern, just adjusting the IDs):

function drop1() {
  if (isAnimating) return; // Block clicks during animation
  
  if(turn == "red" && gameisover == false) {
    if(f1isempty == true){
      animatePieceDrop(1, "F1", "#f44256");
      f1isempty = false;
      f1isred = true;
    } else if(e1isempty == true){
      animatePieceDrop(1, "E1", "#f44256");
      e1isempty = false;
      e1isred = true;
    } else if(d1isempty == true){
      animatePieceDrop(1, "D1", "#f44256");
      d1isempty = false;
      d1isred = true;
    } else if(c1isempty == true){
      animatePieceDrop(1, "C1", "#f44256");
      c1isempty = false;
      c1isred = true;
    } else if(b1isempty == true){
      animatePieceDrop(1, "B1", "#f44256");
      b1isempty = false;
      b1isred = true;
    } else if(a1isempty == true){
      animatePieceDrop(1, "A1", "#f44256");
      a1isempty = false;
      a1isred = true;
    } else {
      alert("Looks like that column is filled up! Let's try another one, shall we?");
    }
    // Switch turn here if your code doesn't handle it elsewhere
  } else if(turn == "blue" && gameisover == false) {
    if(f1isempty == true){
      animatePieceDrop(1, "F1", "#4183f4");
      f1isempty = false;
      f1isblue = true;
    } else if(e1isempty == true){
      animatePieceDrop(1, "E1", "#4183f4");
      e1isempty = false;
      e1isblue = true;
    } else if(d1isempty == true){
      animatePieceDrop(1, "D1", "#4183f4");
      d1isempty = false;
      d1isblue = true;
    } else if(c1isempty == true){
      animatePieceDrop(1, "C1", "#4183f4");
      c1isempty = false;
      c1isblue = true;
    } else if(b1isempty == true){
      animatePieceDrop(1, "B1", "#4183f4");
      b1isempty = false;
      b1isblue = true;
    } else if(a1isempty == true){
      animatePieceDrop(1, "A1", "#4183f4");
      a1isempty = false;
      a1isblue = true;
    } else {
      alert("Looks like that column is filled up! Let's try another one, shall we?");
    }
    // Switch turn here if your code doesn't handle it elsewhere
  }
}

Quick Tweaks to Perfect It

  • Adjust Fall Speed: Change the 0.5s value in the .falling-piece transition to make the fall faster (e.g., 0.3s) or slower (e.g., 0.7s).
  • Match Sizes: Ensure the .falling-piece width/height exactly matches your .hole buttons so it lines up perfectly.
  • Turn Switch: Don’t forget to handle switching turns after the animation finishes (either in the transitionend handler or after calling animatePieceDrop).

This solution keeps your existing code structure intact while adding that satisfying natural fall effect—no jQuery required!

内容的提问来源于stack exchange,提问作者Reilly Ford

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:49:49