【web】纯JavaScript实现window经典纸牌游戏
本帖最后由 含笑阁 于 2019-3-21 10:53 编辑写在最开头:JS无所不能!!!
昨天刚好看到html5新功能中的拖放事件,于是心血来潮,想用这个功能做一个纸牌游戏。
目前有个小?Bug,不能同时拖动多张扑克;{:301_1008:}
测试地址:http://www.lingmx.com/poker/
接下来给大家说一下思路,以及实现的代码
先把最先单的CSS和HTML代码片段发出来吧,只有CSS和HTML的话,效果显示如下:
CSS代码片段:
body {
margin: 0;
padding: 0;
background: url(img/bg.png);
}
#main {
width: 100%;
height: 100%;
}
.nav {
width: 100%;
height: 200px;
display: flex;
justify-content: space-around;
align-items: center;
}
#allPoker,
#fourPokers {
display: flex;
justify-content: space-around;
align-items: center;
}
#fourPokers div,
#sevenPokers div,
#allPoker div {
width: 105px;
height: 150px;
margin: 0 20px;
box-sizing: border-box;
border: 2px solid rgba(255, 255, 255, 0.6);
border-radius: 5px;
cursor: pointer;
position: relative;
}
#fourPokers div img,
#sevenPokers div img,
#allPoker div img {
position: relative;
border-radius: 5px;
}
#allPoker div:nth-child(1).active:after {
content: "";
width: 105px;
height: 150px;
position: absolute;
left: 0;
top: 0;
background: url(img/01.png);
}
#sevenPokers {
display: flex;
justify-content: space-around;
align-items: center;
}
#fourPokers div img,
#sevenPokers div img,
#allPoker div img {
position: absolute;
left: 0;
top: 0;
}
HTML代码片段:
<div id="main">
<!-- 顶部牌堆 -->
<div class="nav">
<!-- 左侧牌堆 -->
<div id="allPoker">
<div class="active"></div>
<div></div>
</div>
<!-- 右侧4个牌堆 -->
<div id="fourPokers">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<!-- 底部 7个牌堆-->
<div id="sevenPokers">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
首先:说一下思路,网页整体分为三个关键位置
1.左上角主牌堆
2.右上角4个放置牌的区域
3.下方7个牌堆
我们需要床架一个随机生成没有重复的0~51的数保存到数组中【共52张扑克,没有大小王】,
然后把所有的图片对象保存到另一个数组中,通过第一个数组中保存的下标去取第二个数组中的图片,
这样就能保证每次取出的图片都是随机的
接下来就是按照游戏规则修改拖放事件和拖放释放事件
好了,接下来是正题:
直接放出完整的代码吧:我在代码里加了详细?的注释应该可以看的明白
// 循环遍历将poker图片添加到数组中
var pokersList = [];
var flower = 0;
for (var i = 1; i <= 52; i++) {
var poker = new Image();
poker.src = "img/" + i + ".jpg"
poker.setAttribute("data-i",i-flower*13); //保存扑克的值
poker.setAttribute("data-flower",flower); //保存扑克的花色
pokersList.push(poker);
if(i%13==0){flower++}
}
console.log(pokersList);
//随机生成长度为52的数组 保存下标,0~51;
var pokerObjI = [];
for (var i = 0; pokerObjI.length < 52; i++) {
var num = Math.floor(Math.random() * 52);
var isRepeat = false;
for (var item of pokerObjI) {
if (item == num) {
isRepeat = true;
}
}
if (!isRepeat) {
pokerObjI.push(num);
}
}
// -----------------向所有牌堆中添加扑克-----------------
// 创建全局变量 pokerNum 来保存以添加过的最后一个下标
var pokerNum = 0;
// 获取牌堆对象
var allPoker = document.getElementById('allPoker').children;
// 向牌堆中插入24张扑克
for (var i = 0; i < 24; i++) {
allPoker.appendChild(pokersList]);
pokerNum++; //同时样poker的下标增加
}
// 向下方7个牌堆中分别保存 1,2,3,4,5,6,7张扑克(共28张)
// 获取7个牌堆对象
var sevenObj = document.getElementById('sevenPokers').children;
// console.log(sevenObj)
// 循环向牌堆中添加扑克
for (var i = 1; i <= 7; i++) {
for (var j = 1; j <= i; j++) {
sevenObj.appendChild(pokersList]);
pokerNum++;
}
}
// ----------------为下方7个牌堆添加层叠样式-----------------
// 给除最后一张扑克外添加active样式
function addClass(){
for (var item of sevenObj) {
var items = item.children;
try{
for(var j of items){
var src = j.getAttribute("data-src");
if(src !==null){j.src = src;j.removeAttribute("data-src")};
}
}catch(e){
//TODO handle the exception
}
if (items.length > 1) {
for (var i = items.length - 2; i >= 0; i--) {
items.setAttribute("data-src", items.src);
items.src = "img/01.png";
}
}
}
}
// 判断7个牌堆中如果有最后一个扑克均为背面,则让最后一个变为正面,
// 如果最后一个为正面,则什么都不改变
function changeClass(){
for (var item of sevenObj){
var lastItem = item.children;
var penultimate = item.children;
if(item.children.length>0){
if(penultimate==undefined){
if(lastItem.dataset.src!=null){
console.log(lastItem);
console.log(lastItem.src);
console.log(lastItem.dataset.src);
lastItem.src = lastItem.dataset.src;
}
}else if(penultimate.src == lastItem.src){
// 如果倒数第二个扑克和倒数第一个扑克src相等,让最后一个变为正面
lastItem.src = lastItem.dataset.src;
}
}
}
}
// 给扑克添加上外边距 让他们分开
function addMarginTop() {
for (var item of sevenObj) {
var items = item.children;
for(var i of items){
i.removeAttribute("style");
}
if (items.length > 1) {
for (var i = 1; i < items.length; i++) {
items.style.marginTop = i * 30 + "px";
}
}
}
}
// 调用上方的函数
addClass();
addMarginTop();
// ----------在所有扑克分发结束后绑定事件----------
//为牌堆中poker绑定点击事件 [点击显示一张,全部显示完后再次点击让所有牌回到牌堆]
// 1.获取到所有牌堆中的扑克
var AllpokerObj = allPoker.getElementsByTagName('img');
// 2.获取牌堆展示的div
var AllpokerDiv = allPoker.nextElementSibling;
// 创建变量保存被拖动的扑克和展示区域当前已添加的扑克数
var thisPoker, pakerListNum;
// 创建变量保存当前被拖动扑克的花色和值
var thisI,thisFlower;
// 为牌堆添加点击事件
allPoker.onclick = function() {
// 将展示区域的所有扑克保存在list中
var pokerList = AllpokerDiv.getElementsByTagName('img');
// 创建变量保存展示区域扑克个数
pakerListNum = pokerList.length;
// console.log(pokerList);
if (AllpokerObj.length > 0) {
AllpokerDiv.appendChild(AllpokerObj); //将最后一张扑克(最上方的),移动到展示区域
if (AllpokerObj.length == 0) {
allPoker.classList.remove('active')
} //如果牌堆没有扑克了,去掉active样式(取消扑克背面样式)
} else {
allPoker.classList.add('active') //为牌堆添加active样式
for (var i = pakerListNum - 1; i >= 0; i--) {
allPoker.appendChild(pokerList); //循环遍历将展示区域扑克添加到牌堆中
}
}
// console.log(pakerListNum);
// 为牌堆展示框中所有扑克绑定拖动事件写在点击事件里,每次点击都更新
// 创建变量保存鼠标位置
var left, top;
for (item of pokerList) {
item.ondragstart = function(e) {
console.log("拖动开始")
thisPoker = this;
thisI = this.dataset.i;
thisFlower = this.dataset.flower;
//保存当前鼠标在扑克上的位置
left = e.clientX - this.offsetLeft;
top = e.clientY - this.offsetTop;
}
item.ondrag = function(e) {
// console.log("拖动ing~")
// 设置当前扑克的位置
//this.style.position = "fixed"
this.style.top = e.clientY - top + "px";
this.style.left = e.clientX - left + "px";
}
item.ondragend = function() {
console.log("拖动结束")
// 移除之前添加的样式
this.removeAttribute("style")
}
}
}
// 为7个牌堆的最后一个扑克添加拖动事件
function addDrag(){
for (var item of sevenObj) {
var list = item.children;
var left,op,style;
if(list){
list.ondragstart = function(e) {
console.log("拖动开始")
thisPoker = this;
thisI = this.dataset.i;
thisFlower = this.dataset.flower;
//保存当前鼠标在扑克上的位置
}
list.ondrag = function(e) {
}
list.ondragend = function() {
console.log("拖动结束")
// 移除之前添加的样式
//this.removeAttribute("style");
//this.setAttribute("style",style);
}
}
}
}
addDrag();
// 为4个牌堆添加拖动释放事件
// 获取4个牌堆
var fourPokers = document.getElementById('fourPokers').children;
for (var item of fourPokers) {
item.ondragenter = function() {
console.log("拖动进入")
}
item.ondragover = function(e) {
e.preventDefault();
console.log("拖动悬停")
}
item.ondragleave = function() {
console.log("拖动离开")
}
item.ondrop = function() {
console.log(this.children.length)
// 当本牌堆里没有扑克时,只可放入A,即thisI为1的扑克
if(this.children.length==0){
// 判断当前拖动的扑克的值不等于1则停止运行 return
if(thisI != 1){
console.log("只可放入A");
return;
}
}else{ // 当牌堆中有扑克时,先判断当前拖动扑克的值和花色,如果与牌堆中的花色不同and值不大于最后一个扑克1时,停止运行
// 获取当前牌堆的data-i和data-flower
var itemI = parseInt(this.dataset.i);
var itemFlower = this.dataset.flower;
if(thisFlower != itemFlower || (thisI - itemI) != 1){
console.log("仅可放入同花色且值仅能比当前值大1")
return;
}
}
console.log("拖动释放")
console.log(thisPoker);
console.log(thisI);
console.log(thisFlower);
console.log(this);
this.appendChild(thisPoker);
this.setAttribute("data-i",thisI);
this.setAttribute("data-flower",thisFlower);
for(var i of this.children){
i.removeAttribute("style");
}
addDrag();
changeClass();
// pakerListNum--;
}
}
// 为下方7个牌堆添加拖动释放事件
for(var item of sevenObj){
item.ondragenter = function() {
console.log("拖动进入")
}
item.ondragover = function(e) {
e.preventDefault();
console.log("拖动悬停")
}
item.ondragleave = function() {
console.log("拖动离开")
}
item.ondrop = function() {
console.log(this.children.length)
if(this.children.length==0){
// 当本牌堆里没有扑克时,只可放入K,即thisI为13的扑克
// 判断当前拖动的扑克的值不等于1则停止运行 return
if(thisI != 13){
console.log("只可放入K");
return;
}
}else{
var thisItem = this.children;
var itemI = parseInt(thisItem.dataset.i);
var itemFlower = parseInt(thisItem.dataset.flower);
if(thisFlower%2 == itemFlower%2 || itemI - thisI !=1){
console.log("只能放置不同的花色,并且值执行相差1")
return;
}
}
console.log("拖动释放");
this.appendChild(thisPoker)
for(var i of this.children){
i.removeAttribute("style");
}
addDrag();
addMarginTop();
changeClass();
// pakerListNum--;
}
}
打包下载:https://www.lanzouj.com/i3hz4ih
本帖最后由 随风浅忆 于 2019-5-22 20:19 编辑
我在楼主的基础上进行了部分修改
[*]结构分离:将css和js从HTML里分离为单个文件
[*]去除了左上角牌堆的背景图
[*]牌组数组的img预设为背面,在显示时将其翻面
[*]删除addClass()函数,在向下方七个牌堆添加牌时判断是否为最下一张,并将其翻为正面
[*]修改了牌堆点击事件内的牌堆翻面和恢复
[*]添加新变量thisList(Array),保存在下方牌堆拖动牌时的拖拽牌下方的牌
[*]在下方牌堆ondrop事件下判断thisList是否为空,若不为空则将其中的牌同时移动到目标牌堆
沙发支持!最爱Windows纸牌。 有意思,js能干的是多,不过node.js性能不好啊…… 感谢楼主分享 xiexiegnexiang 支持一下 大佬,厉害👍 没看明白,学习中,不太玩游戏 厉害了,竟然能用HTML5作出这游戏,膜拜……
页:
[1]
2