Я делаю игру «Соедини четыре», и прямо сейчас я могу вставить фишку в соответствующий слот, а также заменить красную фишку на желтую. Однако, когда вы роняете чип, он не входит в плату. Он наслоен снаружи платы. Я хотел бы, чтобы чип, который сбрасывается, падал на темно-синий круг в каждом слоте и попадал под сам слот. Так что это будет выглядеть реалистично и 3D.
Я думал, что смогу сделать это с помощью z-index, но у меня есть 2 проблемы. 1-й Когда я установил для слотов div z-индекс 3, хотя падающий чип имеет z-индекс 2; чип все еще падает через слот? Во-вторых, даже если бы это сработало, темно-синий круг в каждом слоте теперь был бы скрыт, потому что у div более высокий z-индекс, они должны быть одинаковыми, чтобы оба были видны. Но если они одинаковые, чип не может попасть в плату?
Любые идеи о том, как сделать этот эффект?
//grab all slot positions on the board
const slots = document.querySelectorAll('.board div');
let player = 'p1';
let board = [
0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41,
]
//assign a class to each slot to represent its position
for(let i = 0; i < slots.length; i++) {
//add class to each div
slots[i].classList.add('c' + i);
//add the slot to each div
let slot = document.createElement('span');
slots[i].appendChild(slot);
//add the function with the game logic to each slot
slots[i].addEventListener('click', runGame);
}
function runGame() {
//figure out which column the selected slot sits in
const slotColumn = (Number(this.className.slice(1, 3)) % 7);
//create an array to store all the slots that share the above column
const columnArray = [];
//grab all the slots that sit in that column
for(let i = 0; i < board.length; i++) {
if (board[i] % 7 === slotColumn) columnArray.push(board[i]);
}
//drop chip in the chosen column
dropChip(columnArray);
function dropChip(column) {
//select bottom most slot that's available in the column
for(let i = column.length - 1; i >= 0; i--) {
if (column[i] !== 'p1' || column[i] !== 'p2') {
board[column[i]] = player;
slots[column[i]].classList.add(player);
switchPlayer(player);
break;
}
}
function switchPlayer(currentPlayer) {
if (currentPlayer === 'p1') player = 'p2';
else if (currentPlayer ==='p2') player = 'p1';
}
}
}/** {
outline: 1px solid red;
}*/
*, *:before, *:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
background-color: #e5e6e8;
}
body {
display: flex;
justify-content: center;
min-height: 100vh;
}
.board-wrapper {
padding-top: 100px;
display: flex;
justify-content: center;
margin: auto auto 0 auto; /*ask why this is needed*/
position: relative;
overflow: hidden;
}
.board {
display: flex;
flex-wrap: wrap;
max-width: 706px;
background-color: #00c;
padding: 3px;
}
.board div {
width: 100px;
height: 100px;
background-color: blue;
border: 3px solid #00c;
position: relative;
z-index: 3;
}
.board div span {
display: inline-block;
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #00c;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
box-shadow: inset 0px 0px 13px #0606aa;
}
.board .chip {
display: block;
position: absolute;
background-color: transparent;
top: 0;
left: 0;
right: 0;
height: 100px;
}
.board .chip:after {
content: "";
width: 80px;
height: 80px;
border-radius: 50%;
background-color: red;
position: absolute;
left: 3px;
top: 0;
opacity: 0;
transition: all .5s ease;
}
.board .chip:before {
content: "";
width: 50px;
height: 50px;
border-radius: 50%;
background-color: red;
position: absolute;
left: 18px;
top: 15px;
z-index: 1;
box-shadow: inset 0px 0px 20px #cc0000;
opacity: 0;
transition: all .5s ease;
}
.board div:nth-of-type(7n+1):hover ~ .chip:after{transform: translateX(10px); opacity: 1;}
.board div:nth-of-type(7n+1):hover ~ .chip:before{transform: translateX(10px); opacity: 1;}
.board div:nth-of-type(7n+2):hover ~ .chip:after{transform: translateX(110px); opacity: 1;}
.board div:nth-of-type(7n+2):hover ~ .chip:before{transform: translateX(110px); opacity: 1;}
.board div:nth-of-type(7n+3):hover ~ .chip:after{transform: translateX(210px); opacity: 1;}
.board div:nth-of-type(7n+3):hover ~ .chip:before{transform: translateX(210px); opacity: 1;}
.board div:nth-of-type(7n+4):hover ~ .chip:after{transform: translateX(310px); opacity: 1;}
.board div:nth-of-type(7n+4):hover ~ .chip:before{transform: translateX(310px); opacity: 1;}
.board div:nth-of-type(7n+5):hover ~ .chip:after{transform: translateX(410px); opacity: 1;}
.board div:nth-of-type(7n+5):hover ~ .chip:before{transform: translateX(410px); opacity: 1;}
.board div:nth-of-type(7n+6):hover ~ .chip:after{transform: translateX(510px); opacity: 1;}
.board div:nth-of-type(7n+6):hover ~ .chip:before{transform: translateX(510px); opacity: 1;}
.board div:nth-of-type(7n+7):hover ~ .chip:after{transform: translateX(610px); opacity: 1;}
.board div:nth-of-type(7n+7):hover ~ .chip:before{transform: translateX(610px); opacity: 1;}
.p1:after {
content: "";
display: inline-block;
width: 80px;
height: 80px;
border-radius: 50%;
background-color: red;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 1;
animation-name: drop;
animation-fill-mode: forwards;
animation-duration: .5s;
animation-timing-function: ease-in;
}
.p1:before {
content: "";
width: 50px;
height: 50px;
border-radius: 50%;
background-color: red;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 2;
box-shadow: inset 0px 0px 20px #cc0000;
animation-name: drop;
animation-fill-mode: forwards;
animation-duration: .5s;
animation-timing-function: ease-in;
}
.p2:after {
content: "";
display: inline-block;
width: 80px;
height: 80px;
border-radius: 50%;
background-color: yellow;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 1;
animation-name: drop;
animation-fill-mode: forwards;
animation-duration: .5s;
animation-timing-function: ease-in;
}
.p2:before {
content: "";
width: 50px;
height: 50px;
border-radius: 50%;
background-color: yellow;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 2;
box-shadow: inset 0px 0px 20px #ced639;
animation-name: drop;
animation-fill-mode: forwards;
animation-duration: .5s;
animation-timing-function: ease-in;
}
@keyframes drop {
from {top: -1500px;}
to {top: 0;}
}<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Connect Four</title>
<link rel = "stylesheet" href = "style.css">
</head>
<body>
<div class = "board-wrapper">
<div class = "board">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<span class = "chip"></span>
</div>
</div>
<script src = "script.js"></script>
</body>
</html>


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вот модифицированная версия вашего кода. Сначала я изменил элемент чипа, чтобы учитывать только один псевдоэлемент вместо двух, и использовал переменную CSS, чтобы легко изменить цвет.
Затем для доски я создал каждую ячейку, используя два элемента, чтобы получить эффект 3D. Вы увидите псевдоэлемент, к которому я применил радиальный градиент, чтобы создать отверстие, и этот слой будет наверху, а чип останется позади:
//grab all slot positions on the board
const slots = document.querySelectorAll('.board div');
let player = 'p1';
let board = [
0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41,
]
//assign a class to each slot to represent its position
for (let i = 0; i < slots.length; i++) {
//add class to each div
slots[i].classList.add('c' + i);
//add the slot to each div
let slot = document.createElement('span');
slots[i].appendChild(slot);
//add the function with the game logic to each slot
slots[i].addEventListener('click', runGame);
}
function runGame() {
//figure out which column the selected slot sits in
const slotColumn = (Number(this.className.slice(1, 3)) % 7);
//create an array to store all the slots that share the above column
const columnArray = [];
//grab all the slots that sit in that column
for (let i = 0; i < board.length; i++) {
if (board[i] % 7 === slotColumn) columnArray.push(board[i]);
}
//drop chip in the chosen column
dropChip(columnArray);
function dropChip(column) {
//select bottom most slot that's available in the column
for (let i = column.length - 1; i >= 0; i--) {
if (column[i] !== 'p1' || column[i] !== 'p2') {
board[column[i]] = player;
slots[column[i]].classList.add(player);
switchPlayer(player);
break;
}
}
function switchPlayer(currentPlayer) {
if (currentPlayer === 'p1') player = 'p2';
else if (currentPlayer === 'p2') player = 'p1';
}
}
}/** {
outline: 1px solid red;
}*/
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
background-color: #e5e6e8;
}
body {
display: flex;
justify-content: center;
min-height: 100vh;
}
.board-wrapper {
padding-top: 100px;
display: flex;
justify-content: center;
margin: auto auto 0 auto; /*ask why this is needed*/
position: relative;
overflow: hidden;
}
.board {
display: flex;
flex-wrap: wrap;
max-width: 706px;
background-color: #00c;
padding: 3px;
}
.board div {
width: 100px;
height: 100px;
position: relative;
}
.board div span {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: #00c;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
box-shadow: inset 0px 0px 13px #0606aa;
}
.board div span:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background: radial-gradient(circle, transparent 40px, blue 0);
border: 3px solid #00c;
z-index: 3;
}
.board .chip {
display: block;
position: absolute;
background-color: transparent;
top: 0;
left: 0;
right: 0;
height: 100px;
}
.board .chip:after {
content: "";
width: 80px;
height: 80px;
border-radius: 50%;
border: 15px solid red;
background-color: red;
box-shadow: inset 0px 0px 20px #cc0000;
position: absolute;
left: 3px;
top: 0;
opacity: 0;
transition: all .5s ease;
}
.board div:nth-of-type(7n+1):hover~.chip:after {
transform: translateX(10px);
opacity: 1;
}
.board div:nth-of-type(7n+1):hover~.chip:before {
transform: translateX(10px);
opacity: 1;
}
.board div:nth-of-type(7n+2):hover~.chip:after {
transform: translateX(110px);
opacity: 1;
}
.board div:nth-of-type(7n+2):hover~.chip:before {
transform: translateX(110px);
opacity: 1;
}
.board div:nth-of-type(7n+3):hover~.chip:after {
transform: translateX(210px);
opacity: 1;
}
.board div:nth-of-type(7n+3):hover~.chip:before {
transform: translateX(210px);
opacity: 1;
}
.board div:nth-of-type(7n+4):hover~.chip:after {
transform: translateX(310px);
opacity: 1;
}
.board div:nth-of-type(7n+4):hover~.chip:before {
transform: translateX(310px);
opacity: 1;
}
.board div:nth-of-type(7n+5):hover~.chip:after {
transform: translateX(410px);
opacity: 1;
}
.board div:nth-of-type(7n+5):hover~.chip:before {
transform: translateX(410px);
opacity: 1;
}
.board div:nth-of-type(7n+6):hover~.chip:after {
transform: translateX(510px);
opacity: 1;
}
.board div:nth-of-type(7n+6):hover~.chip:before {
transform: translateX(510px);
opacity: 1;
}
.board div:nth-of-type(7n+7):hover~.chip:after {
transform: translateX(610px);
opacity: 1;
}
.board div:nth-of-type(7n+7):hover~.chip:before {
transform: translateX(610px);
opacity: 1;
}
.p1:after,
.p2:after {
content: "";
display: inline-block;
width: 80px;
height: 80px;
border-radius: 50%;
border: 15px solid var(--c, red);
background-color: var(--c, red);
box-shadow: inset 0px 0px 20px var(--s, #cc0000);
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
z-index: 1;
animation-name: drop;
animation-fill-mode: forwards;
animation-duration: .5s;
animation-timing-function: ease-in;
}
.p2 {
--c: yellow;
--s: #ced639;
}
@keyframes drop {
from {
top: -1500px;
}
to {
top: 0;
}
}<div class = "board-wrapper">
<div class = "board">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<span class = "chip"></span>
</div>
</div>
Я бы использовал метод, подобный ответу, найденному здесь: stackoverflow.com/questions/41875999/…