本红包雨项目是基于HTML5的游戏框架Phaser写的,最终形成的是一个canvas,所以性能很好,但是必须要说的是这个框架比较大,压缩后也有700K左右,所以请慎用.

代码地址: https://github.com/AmosXu/red-packet-rain

1. 效果展示

       

图片依次是倒计时页面,抢红包页面,拆红包页,红包展示页,这些页面都是写在一个canvas里面的,无刷新的切换效果,性能超级棒

2.代码展示

贴上主要的代码js代码和注释

  //初始化图片let imgjishi = 'assets/img/daojishi.png'let bgPlan = 'assets/img/bg-plan.jpg'let bgRainer = 'assets/img/bg-rainer.jpg'let redpacket = 'assets/img/redpacket.png'let close = 'assets/img/close.png'let dialogExit = 'assets/img/dialog-exit.png'let buttonCancel = 'assets/img/button-cancel.png'let buttonExit = 'assets/img/button-exit.png'let openRedpacket = 'assets/img/open-redpacket.png'let open = 'assets/img/open.png'let redpacketResult = 'assets/img/redpacket-result.png'let buttonUseTicket = 'assets/img/button-use-ticket.png'let buttonContinue = 'assets/img/button-continue.png'let cursorAnimation = 'assets/img/cursor-animation.png'let states = {}let QingLvGroup;let hitNum = 0;let config = {selfPool:40,selfPic:'redpacket',rate:0.5,maxSpeed:1200,minSpeed:400,max:95}let ids = [0, 1, 2, 3, 4, 5]let redpackets = ['全场优惠50元', '20元代金券', '全场优惠50元', '20元代金券', '全场优惠50元', '20元代金券']let time = 25;let getIds = []let radio = document.documentElement.clientWidth/375;
  let e;function rfuc(n){return n*radio;}//初始化红包function QingLv(config, game){this.init = function(){this.config = config;QingLvGroup = game.add.group();QingLvGroup.enableBody = true;QingLvGroup.createMultiple(config.selfPool, config.selfPic); //初始化多个红包QingLvGroup.setAll('anchor.y',1)QingLvGroup.setAll('outOfBoundsKill', true);QingLvGroup.setAll('checkWorldBounds', true);this.maxWidth = game.width + 300;game.time.events.loop(Phaser.Timer.SECOND * config.rate, this.createQL, this);};this.createQL = function(){e = QingLvGroup.getFirstExists(false);if(e) {if(hitNum >= config.max) {return;}hitNum++;e.events.onInputDown.removeAll();var ram= Math.random();ram =ram<0.5?ram+=0.5: ram;e.loadTexture(this.config.selfPic)e.alpha = 1;e.angle = 30// e.scale.setTo(rfuc(ram));e.reset(game.rnd.integerInRange(100, this.maxWidth), 100)  //红包生成的位置e.body.velocity.x = game.rnd.integerInRange(-300, -150);   //红包移动的速度e.body.velocity.y = game.rnd.integerInRange(config.minSpeed, config.maxSpeed);e.inputEnabled = true;e.events.onInputDown.add(this.hitted, this)}};this.hitted = function(sprite){if(Math.random() < 1/4 && ids.length > 0) {
          sprite.kill();//点击获得红包,游戏暂停game.paused = true;//背景let hexGraphics = new Phaser.Graphics().beginFill(0x000000, 0.5).drawRect(0,0,document.documentElement.clientWidth,document.documentElement.clientHeight + 2);let pausedMask = game.add.sprite(0, 0, hexGraphics.generateTexture())let openDialog = game.add.sprite(rfuc(62), rfuc(150), 'openRedpacket')let open = game.add.sprite(rfuc(130), rfuc(300), 'open')open.inputEnabled = true;let result = game.add.sprite(rfuc(0), rfuc(120), 'redpacketResult')result.visible = falselet userTicket = game.add.sprite(rfuc(78), rfuc(445), 'buttonUseTicket')userTicket.visible = falselet goOn = game.add.sprite(rfuc(198), rfuc(445), 'buttonContinue')goOn.visible = falselet ticketText = {};let link = ''//拆红包let clickOpen = function() {//游戏暂停时,点击事件无效,只能通过这种画热点的形式来绑定事件let openRect = new Phaser.Rectangle(rfuc(130), rfuc(315), 239, 239).copyFrom(open);if (openRect.contains(game.input.x, game.input.y)) {let currentWidth = open.width//拆红包动画let tempArr = [2, 4, 8, 4, 2, 1]let index = 0;let timer = setInterval(function() {if (index > tempArr.length-1) { index = 0 }open.width = currentWidth / tempArr[index]open.height = open.heightopen.left = game.world.centerX - open.width / 2++index}, 200)game.input.onDown.remove(clickOpen, this);let arrIndex = Math.floor(Math.random() * ids.length)let redpacketId = ids.splice(arrIndex, 1)getIds.push(redpacketId[0])setTimeout(()=> {timer && clearInterval(timer)document.getElementById('audioOpen').play()let text = redpackets[redpacketId[0]]ticketText = game.add.text(0, rfuc(338), text, {fill: '#ffe67d', fontSize: '46px', fontWeight: 'bolder'})ticketText.left = game.world.centerX - ticketText.width / 2    //文字相对于屏幕左右居中openDialog.visible = falseopen.visible = falseresult.visible = trueuserTicket.visible = truegoOn.visible = truegame.input.onDown.add(clickButton, this)}, 1000)} };let clickButton = function() {let userTicketRect = new Phaser.Rectangle(rfuc(78), rfuc(445), 194, 66).copyFrom(userTicket);let continueRect = new Phaser.Rectangle(rfuc(198), rfuc(445), 194, 66).copyFrom(goOn);if (userTicketRect.contains(game.input.x, game.input.y)) {window.location.replace(link)game.input.onDown.remove(clickButton, this);} else if (continueRect.contains(game.input.x, game.input.y)) {result.visible = falseuserTicket.visible = falsegoOn.visible = falsepausedMask.visible = falseticketText.visible = falsegame.paused = falsegame.input.onDown.remove(clickButton, this);}}game.input.onDown.add(clickOpen, this)} else {sprite.inputEnabled = false;var anim = sprite.animations.add(config.selfPic);sprite.play(config.selfPic, 40, false);anim.onComplete.add(this.fade, this, sprite)  }};this.fade = function(sprite){var tween = game.add.tween(sprite).to({alpha:0}, 300, 'Linear', true)tween.onComplete.add(this.killed, this, sprite);};this.killed = function(sprite){sprite.kill();}}states.boot = function(game) {this.preload = function() {if (typeof(GAME) !== "undefined") {this.load.baseURL = GAME + "/";}if (!game.device.desktop) {this.scale.scaleMode = Phaser.ScaleManager.EXACT_FIT;this.scale.forcePortrait = true;this.scale.refresh();}};this.create = function() {game.stage.backgroundColor = '#FFF';game.state.start('preload');};};states.preload = function(game) {this.preload = function(game) {//加载图片game.load.spritesheet('daojishi', imgjishi, 250,120, 4)game.load.image('bgPlan', bgPlan)game.load.image('bgRainer', bgRainer)game.load.spritesheet('redpacket', redpacket, 144, 173, 2)game.load.image('close', close)game.load.image('dialogExit', dialogExit)game.load.image('buttonExit', buttonExit)game.load.image('buttonCancel', buttonCancel)game.load.image('openRedpacket', openRedpacket)game.load.image('open', open)game.load.image('redpacketResult', redpacketResult)game.load.image('buttonContinue', buttonContinue)game.load.image('buttonUseTicket', buttonUseTicket)game.load.spritesheet('cursorAnimation', cursorAnimation, 74, 108, 2)};this.create = function() {game.state.start('main');};};states.main = function(game) {this.create = function() {// 物理系统
          game.physics.startSystem(Phaser.Physics.ARCADE);// 背景图var bgPlan = game.add.sprite(0, 0, 'bgPlan');bgPlan.width = game.width;bgPlan.height = game.height;var cursorPointer = game.add.sprite(game.world.centerX - 36, game.world.centerY + 86, 'cursorAnimation');var anim = cursorPointer.animations.add('cursorAnimation');cursorPointer.play('cursorAnimation', 2, true);document.getElementById('audioCountDown').play()// 开始游戏倒计时var daojishi = game.add.sprite(game.world.centerX - 140, game.world.centerY - 400, 'daojishi');var anim = daojishi.animations.add('daojishi');daojishi.play('daojishi', 1, false);anim.onComplete.add(this.startGame, this, daojishi);};this.startGame = function(daojishi){this.leftTime = timelet bgRainer = game.add.sprite(0, 0, 'bgRainer');bgRainer.width = game.width;bgRainer.height = game.height;daojishi.visible = false;this.createQingLv();//添加按钮,并绑定事件let closeImg = game.add.button(rfuc(20), rfuc(20), 'close', function(){game.paused = truepausedMask.visible = trueexitDialog.visible = trueexitButton.visible = truecancelButton.visible = truegame.input.onDown.add(buttonClick, this)}.bind(this))// 剩余时间this.leftTimeText = game.add.text(0, 0, this.leftTime, {fill: '#FFF', fontSize: '40px', fontWeight: 'bolder'})this.leftTimeText.scale.setTo(rfuc(1))this.leftTimeText.fixedToCamera = true;this.leftTimeText.cameraOffset.setTo(game.camera.width - rfuc(80), rfuc(20));let hexGraphics = new Phaser.Graphics().beginFill(0x000000, 0.5).drawRect(0,0,document.documentElement.clientWidth,document.documentElement.clientHeight + 2);let pausedMask = game.add.sprite(0, 0, hexGraphics.generateTexture())pausedMask.visible = false;let exitDialog = game.add.sprite(rfuc(62), rfuc(150), 'dialogExit')exitDialog.visible = false;let exitButton = game.add.button(rfuc(80), rfuc(315), 'buttonExit')exitButton.visible = false;let isExit = falselet cancelButton = game.add.button(rfuc(200), rfuc(315), 'buttonCancel')cancelButton.visible = false;game.time.events.repeat(Phaser.Timer.SECOND, this.leftTime, this.refreshTime, this)let buttonClick = function() {let cancelRect = new Phaser.Rectangle(rfuc(200), rfuc(315), 194, 66).copyFrom(cancelButton);if (cancelRect.contains(game.input.x, game.input.y)) {game.input.onDown.remove(buttonClick, this)game.paused = falsepausedMask.visible = falseexitDialog.visible = falseexitButton.visible = falsecancelButton.visible = false}}};this.createQingLv = function(){this.qinglv = new QingLv(config, game);this.qinglv.init();this.qinglv = new QingLv(config, game);this.qinglv.init();};this.refreshTime = function(){this.leftTime--;var tem = this.leftTime;this.leftTimeText.text = tem;if(this.leftTime === 0) {game.paused = true;}}};//生成游戏let game = nullif (game == null) {game = new Phaser.Game(document.documentElement.clientWidth, document.documentElement.clientHeight + 2, Phaser.AUTO, document.getElementById('gameScreen'));game.state.add('boot', states.boot.bind(game));game.state.add('preload', states.preload.bind(game));game.state.add('main', states.main.bind(game));game.state.start('boot');}

3. 疑难问题

1. 游戏暂停时,点击事件无效,需要点击,怎么解决

答:  通过全局事件画热点的形式绑定事件,一定要记得移除事件,一定一定要记得

game.input.onDown.add(clickOpen, this)   //给游戏绑定全局事件

let userTicket = game.add.sprite(rfuc(78), rfuc(445), 'buttonUseTicket')
let userTicketRect = new Phaser.Rectangle(78, 445, 194, 66).copyFrom(userTicket);  //获得button的区域//如果点击的位置为button的位置就执行下一步
if (userTicketRect.contains(game.input.x, game.input.y)) {//移除全局事件game.input.onDown.remove(clickButton, this);
}

2. 文字或图片相对于屏幕居中(暂时只能做屏幕居中)

答: 添加文字到游戏中,文字向左的偏移量等于游戏屏幕的宽度减去文字宽度的一般,就能达到居中的效果

ticketText = game.add.text(0, rfuc(338), '我想居中', {fill: '#ffe67d', fontSize: '46px', fontWeight: 'bolder'})
ticketText.left = game.world.centerX - ticketText.width / 2    //文字相对于屏幕左右居中

代码地址: https://github.com/AmosXu/red-packet-rain

 

转载于:https://www.cnblogs.com/mianbaodaxia/p/7095782.html

仿淘宝,京东红包雨(基于Phaser框架)相关推荐

  1. 纯css仿淘宝京东导航菜单栏

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  2. 仿淘宝京东商品规格属性选择的最简单实现

    仿淘宝京东商品规格属性选择的最简单实现 商城里面的规格选择,网上大部分是自定义控件实现的,显得很是麻烦,而我的实现方式是大家最常用的控件RecyclerView,特点是性能好,简单.废话不多说,先看实 ...

  3. JavaScript仿淘宝京东放大镜效果(鼠标事件)------JavaScript学习之路10

    JavaScript仿淘宝京东放大镜效果 注意 一定计算好放大比例,本程序放大5倍,具体放大倍数,自定 效果 完整源码 <!DOCTYPE html> <html lang=&quo ...

  4. Android仿淘宝京东商品规格参数颜色筛选

    Android 选择商品属性sku 最近项目中使用SKU属性查询,类似淘宝京东商品的选择,在网上查询了弄了几个源码看看,发现还是实现不了多属性选择问题,再原基础上改动相当费事,所以想干脆自己处理这个问 ...

  5. Android 仿淘宝京东等我的订单界面及任意列表拓展

    概述 目前像淘宝及展示列表等都有多个item展示的需求,可能大多数如果没做过,第一眼就是ListView去嵌套ListView,虽然这样是可以完成,但是这样做会导致手机过度绘制,为什么呢?因为当一个I ...

  6. 仿淘宝菜单分类页面布局--iframe框架有限替代方案

    之前做一些类似后台管理界面,典型的左侧菜单.右侧布局,基本都采用iframe框架来完成 虽然iframe操作起来非常方便,但是也存在问题,例如页面不够美观,css样式布局会出现各种复杂问题以至于显得比 ...

  7. java B2B2C 仿淘宝电子商城系统-基于Rabbitmq实现延迟消息

    预备知识 1.1 消息传递 首先我们知道消费者是从队列中获取消息的,那么消息是如何到达队列的? 当我们发送一条消息时,首先会发给交换器(exchange),交换器根据规则(路由键:routing ke ...

  8. vue仿淘宝京东商品多条件筛选(vue实现)

    <template><div id="warp">你选择的是:<mark v-for="(item,index) in arr"& ...

  9. Android 仿淘宝京东商品详情页阻力翻页效果

    原文链接:http://code.taobao.org/p/android-example/diff/46/trunk/%E5%95%86%E5%9F%8E%E8%AF%A6%E6%83%85/src ...

  10. Android 仿淘宝京东商品详情视频+图片与图片第一帧获取

    近日项目有个新需求就是把原本的商品详情只有图片展示,改为视频+图片方式展示. 此博客只提供记录,与思路具体根据自己需求实现.首先想到的是Google搜索下别人的实现方式来参考实现发现不怎么适合项目需求 ...

最新文章

  1. 深度学习处在大爆炸时代的边缘
  2. cannot import name '_C'
  3. 《程序员修炼之道》笔记(一)
  4. 科创板注册获批,优刻得将成为“公有云第一股”
  5. react-navigation(6.0.6版本)使用详解(基于RN0.65*版本)
  6. 光电整纬机(日本世联电子株式会社)
  7. R语言各个包里面的数据集
  8. 算法与数据结构 第2章 排序基础 上
  9. 用WPS2000制作勾股定理教学课件(转)
  10. 数字音频水印技术的matlab代码,数字水印技术dct算法matlab源代码
  11. 数学建模更新10(蒙特卡罗模拟)
  12. 如何成为区块链开发人员
  13. 解决MacBook无法读写移动硬盘的问题
  14. linux怎么查看hwaddr_Linux查看MAC地址方法
  15. AndroidTV开发教程(1)
  16. 笔记本散热不好怎么办
  17. c语言编译功率谱密度函数,科学网—6、功率谱密度函数估计 - 柏世平的博文
  18. android商店账号密码错误,android app 自定义签名出现错误:Keystore was tampered with, or password was incorrect...
  19. 全排列(从大到小排列)
  20. Canvas3——绘制渐变图形与绘制变形图形

热门文章

  1. 简述osi参考模型各层主要功能_简述OSI参考模型定义及各层的主要功能
  2. 海康web3.0使用记录
  3. 计算机中¥符号按哪个键,人民币键盘符号怎么打 电脑怎么打人民币符号
  4. matlab实现icp算法,ICP算法(Iterative Closest Point)及VTK实现
  5. C51语言检测电平变化,单片机引脚上的电平变化
  6. C语言51单片机怎么读引脚,如何控制51单片机的引脚
  7. 单片机中断程序,如何被中断?
  8. web服务器 怎样上传文件,文件上传web服务器
  9. windows 11系统提示windows许可证即将过期(仅限正版)
  10. matlab中concur怎么用,Matlab的concur、repmat、kron、reshape函数介绍