loadimage怎么使用_使用Canvas实现一个在线发牌游戏 [纯前端、附源码]

写在开头
  • 一位作者开源了这个游戏,纯前端实现,原生Canvas
  • 希望大家给他点个star,源码地址:https://github.com/leeseean/sic-bo
为什么要推荐这个项目
  • 在我看来,这个作者是有一定技术实力的,对canvas理解和使用,以及浏览器渲染机制,都是比较了解的,还有原生dom操作能力都可以
  • 里面大量使用了canvas的路径绘制、填充,以及requestAnimationFrame
技术栈
  • 使用原生javascript + html +css
  • 主要绘制是canvas实现
项目初始状态

43b804e57ff58a931639d5c483f136a1.png

怎么玩这个游戏
  • 点击想押注的地方
  • 筹码会有一个动画飞向你押注的区域
  • dbeb3fd3eb48cc86901e09efffaa2bcd.png

  • 押注完成后,定时开始摇骰子,开奖

76fdfcb3e18463575af1ed520893c93f.png

大概实现
  • 初始调用 init函数,生成canvas画布,挂载onclick事件
   init() {
        let _this = this;
        _this.loadImage();
        _this.scale = screen.width         let scale = _this.scale;
        //拿到画布
        let canvas_fly = document.getElementById('canvas_fly'); //渲染飞出去的筹码
        canvas_fly.width = document.body.clientWidth;
        canvas_fly.height = 912 * scale || 800;
        _this.ctxFly = canvas_fly.getContext('2d');
        let canvas_stop = document.getElementById('canvas_stop'); //渲染未确认投注放桌面上的筹码
        canvas_stop.width = document.body.clientWidth;
        canvas_stop.height = 912 * scale || 800;
        _this.ctxStop = canvas_stop.getContext('2d');
        let canvas_betted = document.getElementById('canvas_betted'); //渲染确认投注的筹码
        canvas_betted.width = document.body.clientWidth;
        canvas_betted.height = 912 * scale || 800;
        _this.ctxBetted = canvas_betted.getContext('2d');

        //拿到chipsImgObj对象
        let img = new Image();
        img.onload = function () {
            _this.chipsImgObj = this; //拿到chipsImgObj对象
        }
        img.src = './images/chips.png';

        //确定所用筹码
        $('.chips>.chip').off('click').on('click', function (e) {
            $(this).addClass('on').siblings('.chip').removeClass('on');
            _this.priceNum = +$(this).attr('priceNum');
        });
        $('.chips>.chip10').trigger('click'); //默认筹码10

        const pieceIntervalOver = { //连续点击翻倍生不生效的flag
            'betFor': false,
            'betted': false,
            'pieceCount': 0,
        };
        const cancelOk = {
            ok: false,
            count: 0,
        }; //取消完毕,默认false
        const resetOk = {
            ok: false,
            count: 0,// 防止重复点击
        }
        //点击桌面选号
        $('[rel="selectCode"]').off('click').on('click', function (e) {
            if (cancelOk.ok || cancelOk.count === 0) {
                cancelOk.count = 0;
            } else {
                return; //没取消完毕不准过去
            }

            _this.flyState = 'flyTo';
            let code = $(this).attr('value');
            let method = $(this).attr('method');
            let startPos = {
                x: $(`.chips .chip${_this.priceNum}`).offset().left,
                y: $(`.chips .chip${_this.priceNum}`).offset().top,
            };
            let endPos = {
                x: $(this).offset().left + $(this)[0].offsetWidth * scale / 2 - $('.chips>.chip').width() * scale / 2,
                y: $(this).offset().top + $(this)[0].offsetHeight * scale / 2 - $('.chips>.chip').height() * scale / 2,
            };
            _this.eachBetCount[code] = _this.eachBetCount[code] || 0;
            _this.eachBetCount[code] += _this.priceNum;
            _this.betOrderRecords[code] = { //记录order
                method: method,
                code: code,
                price: _this.priceNum,
                amount: _this.eachBetCount[code],
                piece: _this.eachBetCount[code],
            };
            let clickedElemOption = { //被点击元素的相关数据
                priceNum: _this.priceNum,
                code: code,
                position: {
                    x: $(this).offset().left,
                    y: $(this).offset().top,
                },
                width: $(this).outerWidth(),
                height: $(this).outerHeight(),
            };
            _this.betForRecords.push({ //记录投注
                elemOption: copyJSON(clickedElemOption),
                priceNum: _this.priceNum,
                startPos,
                endPos,
            });

            _this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, _this.priceNum, startPos, endPos, clickedElemOption, 10);
            $('.betMoneyAmount').text(_this.calculateBetMoney());
        });
        //取消投注
        $('.cancelButton').off('click').on('click', function (e) {
            if (cancelOk.ok || cancelOk.count === 0) {
                cancelOk.ok = false;
            } else {
                return; //没取消完毕不准过去
            }
            if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {

            } else {
                return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效                
            }
            cancelOk.count += 1;

            pieceIntervalOver.pieceCount = 0;
            if (_this.betForRecords.length === 0) {
                return;
            }
            _this.flyState = 'flyBack';
            //timechunk 分时函数
            let i = 0;
            let interval = setInterval(() => {
                if (i === _this.betForRecords.length) {
                    cancelOk.ok = true;
                    cancelOk.count = 0; //回到0
                    _this.betForRecords.length = 0;
                    _this.betOrderRecords = {};
                    _this.eachBetCount = {};
                    _this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
                    $('.betMoneyAmount').text(_this.calculateBetMoney());
                    return clearInterval(interval);
                }
                let record = _this.betForRecords[i];
                _this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, record.priceNum, record.endPos, record.startPos, record.elemOption, 10);
                i++;
            }, 10);
        });
        //重置投注
        $('.resetButton').off('click').on('click', function (e) {
            if (resetOk.ok || resetOk.count === 0) {
                resetOk.ok = false;
            } else {
                return; //没取消完毕不准过去
            }
            if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {

            } else {
                return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效                
            }
            resetOk.count += 1;

            pieceIntervalOver.pieceCount = 0;
            if (_this.betForRecords.length === 0 && _this.bettedRecords.length === 0) {
                return;
            }
            _this.flyState = 'flyBack';
            //timechunk 分时函数
            let i = 0;
            let interval = setInterval(() => {
                if (i === _this.betForRecords.length) {
                    _this.betForRecords.length = 0;
                    _this.betOrderRecords = {};
                    _this.eachBetCount = {};
                    _this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
                    $('.betMoneyAmount').text(_this.calculateBetMoney());
                    clearInterval(interval);
                    let j = 0;
                    const _interval = setInterval(() => {
                        if (j === _this.bettedRecords.length) {
                            resetOk.ok = true;
                            resetOk.count = 0; //回到0
                            _this.bettedRecords.length = 0;
                            _this.ctxBetted.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
                            $('.betMoneyAmount').text(_this.calculateBetMoney());
                            return clearInterval(_interval);
                        }
                        console.log(j)
                        const bettedRecord = _this.bettedRecords[j];
                        _this.chipFly(_this.ctxFly, _this.ctxBetted, _this.chipsImgObj, bettedRecord.priceNum, bettedRecord.endPos, bettedRecord.startPos, bettedRecord.elemOption, 10);
                        j++;
                    }, 10);
                    return;
                }
                const betForRecord = _this.betForRecords[i];
                _this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, betForRecord.priceNum, betForRecord.endPos, betForRecord.startPos, betForRecord.elemOption, 10);
                i++;
            }, 10);

        });
        //确认投注
        $('.betButton').off('click').on('click', function (e) {
            if (_this.betForRecords.length === 0) {
                alert('请先下注!');
                return;
            }
            if (cancelOk.ok || cancelOk.count === 0) {
            } else {
                return; //没取消完毕不准过去
            }
            if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {

            } else {
                return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效                
            }
            _this.flyState = 'betted';
            _this.bettedRecords = _this.bettedRecords.concat(_this.betForRecords);
            _this.betForRecords.forEach((record) => {
                _this.chipFly(_this.ctxFly, _this.ctxBetted, _this.chipsImgObj, record.priceNum, record.endPos, record.endPos, record.elemOption, 30);
            });
            _this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
            _this.betForRecords.length = 0;
            _this.betOrderRecords = {};
            _this.eachBetCount = {};
        });
        //翻倍投注 
        $('.pieceButtoon').off('click').on('click', function (e) {
            let bettedLen = _this.bettedRecords.length;
            let betForLen = _this.betForRecords.length;
            if (bettedLen === 0 && betForLen === 0) {
                return;
            }
            if (cancelOk.ok || cancelOk.count === 0) {
            } else {
                return; //没取消完毕不准过去
            }
            if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {
                pieceIntervalOver.betFor = false;
                pieceIntervalOver.betted = false;
                pieceIntervalOver.pieceCount += 1;
            } else {
                return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效                
            }

            //timechunk分时函数,防止短时间多次触发卡死浏览器
            let i = 0;
            let interval_bet = setInterval(() => {
                if (i === bettedLen) {
                    pieceIntervalOver.betted = true;
                    return clearInterval(interval_bet);
                }
                let code = _this.bettedRecords[i]['elemOption']['code'];
                _this.priceNum = _this.bettedRecords[i]['priceNum'];
                $(`[rel="selectCode"][value="${code}"]`).trigger('click'); //自动桌面选号点击
                i++;
            }, 10);
            let j = 0;
            let interval_betted = setInterval(() => {
                if (j === betForLen) {
                    pieceIntervalOver.betFor = true;
                    return clearInterval(interval_betted);
                }
                let code = _this.betForRecords[j]['elemOption']['code'];
                _this.priceNum = _this.betForRecords[j]['priceNum'];
                $(`[rel="selectCode"][value="${code}"]`).trigger('click'); //自动桌面选号点击
                j++;
            }, 10);
        });
    },
  • init函数初始化中将canvas画笔挂载到this中
_this.ctxStop = canvas_stop.getContext('2d');
_this.ctxBetted = canvas_betted.getContext('2d');
...
  • 确认投注后,清空未确认投注放桌面上的筹码画布
 $('.betButton').off('click').on('click'、、、
 _this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
  • 如果没有下注,就提示:
  if (_this.betForRecords.length === 0) {
                alert('请先下注!');
                return;
            }
最后,希望大家多看看这个源码,了解canvas使用
  • 记得给作者点个star哦,这是一个入门canvas的一个很好的开源项目,点击左下角的阅读原文就可以进入到源码地址啦:https://github.com/leeseean/sic-bo
  • 如果深入点的话,可以再学习一下canvas的像素控制,或者pixijs的使用
  • 在线体验这个游戏的地址是:
  • https://leeseean.github.io/sic-bo/

ece5257d5e8793a7f8c0c844780d6958.png

 相关推荐

Kbone原理解析,小程序技术该如何选型?

Node.js结合ProtoBuffer,从零实现一个redis!

详解 ES10 中 Object.fromEntries() 的缘起

JS执行上下文的两个阶段做了些啥?

让你彻底掌握 TS 枚举

遇到这些 TS 问题你会头晕么?

在 TS 中如何减少重复代码

用上这几招,轻松实现 TS 类型提取

TypeScript 期中考试现在开始

前端学习数据结构与算法系列(八):快速排序与三路快排

前端学习数据结构与算法系列(七):堆排序与归并排序

前端学习数据结构与算法系列(六):选择排序与插入排序

前端学习数据结构与算法系列(五):冒泡排序的理解与实现

前端学习数据结构与算法系列(四):哈希、堆和二叉查找树

前端学习数据结构与算法系列(三):栈与队列的基础知识

前端学习数据结构与算法系列(二):链表与数组的基础知识

前端学习数据结构与算法系列(一):初识数据结构与算法

腾讯文档原来是这样用 webpack5 的 Module federation 特性的!

绝大部分的开源项目都投入TypeScript了!你呢?

【收藏系列】JS灵魂之问(下) - 附个人成长经验分享

【收藏系列】JS灵魂之问, 是否有offer看你接到多少个(中)

【收藏系列】JS灵魂之问, 请问你能接得住几个?(上)

【JS进阶深挖】完全弄懂数据类型转换(上)

0b90967d3c08f2d300d01d9f2fb8c4ac.png

1efd3abf553f09506993b44bd1d72008.png点在看的人特别帅/美 43f36b4fb944333548716894db0bffce.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值