html 做王者荣耀

        相信大家都玩过王者荣耀吧,那么王者荣耀在html中要怎么实现呢?

话不多说,上代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>王者地图</title>
    <script src="./three.min.js"></script>
    <script src="./MOBAControls.js"></script>
    <script src="./DRACOLoader.min.js"></script>
    <script src="./GLTFLoader.min.js"></script>
    <script src="./nipplejs.min.js"></script>
    <script src="./vconsole.min.js"></script>
    <script src="https://cdn.bootcss.com/tween.js/r14/Tween.min.js"></script>
</head>
<style>
    html, body, #output{
        width: 100%;
        height: 100%;
        padding: 0;
        margin: 0;
        overflow: hidden;
    }

    #layer{
        width: 100%;
        height: 100%;
        position: absolute;
        background-color: rgba(211, 226, 226, 0.4);
        top: 0;
        left: 0;
    }

    .loading{
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translateX(-50%) translateY(-50%);
            z-index: 10;
            width: 60px;
            height: 40px;
            margin: 0 auto;
        }
        .loading span{
            display: inline-block;
            width: 8px;
            height: 100%;
            border-radius: 4px;
            background: lightgreen;
            -webkit-animation: load 1s ease infinite;
        }
        @-webkit-keyframes load{
            0%,100%{
                height: 40px;
                background: lightgreen;
            }
            50%{
                height: 70px;
                margin: -15px 0;
                background: lightblue;
            }
        }
        .loading span:nth-child(2){
            -webkit-animation-delay:0.2s;
        }
        .loading span:nth-child(3){
            -webkit-animation-delay:0.4s;
        }
        .loading span:nth-child(4){
            -webkit-animation-delay:0.6s;
        }
        .loading span:nth-child(5){
            -webkit-animation-delay:0.8s;
        }

        .tip{
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translateX(-50%) translateY(20px);
            z-index: 10;
        }
        .tip span{
            color: #0ff
        }
</style>
<body>
    <div id="layer">
            <div class="loading">
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span>
                    <span></span>
            </div>
            <div class='tip'>
                <span>开启屏幕旋转可以横置屏幕</span>
            </div>
    </div>
    <div id="output">

    </div>
</body>
<script>

    // 'dev' / 'prod'
    // const evirenment = 'dev'
    const evirenment = 'prod'

    if(evirenment == 'dev'){new VConsole()}

    window.onload = () => {
        let name = evirenment == 'dev'? '汤圆skr狠人': prompt('请给自己角色取个名字,碰撞检测已暂时被注释', '如: 王xx')
        name = name || '王xx'
        let scene
        let camera
        let renderer
        const init = (dom) => {
            scene = new THREE.Scene()
            
            let ambientLight = new THREE.AmbientLight( 0xffffff)
            scene.add(ambientLight)

            let light = new THREE.DirectionalLight( 0xffffff)
            light.castShadow = true
            light.shadow.camera.left = light.shadow.camera.bottom = -300
            light.shadow.camera.right = light.shadow.camera.top = 300
            light.position.set(10, -50, 100)
            scene.add(light)

            size = {
                width: dom.offsetWidth,
                height: dom.offsetHeight
            }
            camera = new THREE.PerspectiveCamera(45, size.width / size.height, 0.5, 20000)
            evirenment == 'dev'? camera.position.set(30, 30, 30): camera.position.set(30, 30, 30)
            camera.up.set(0, 0, 1)

            renderer = new THREE.WebGLRenderer({
                antialias: true,
                alpha: true
            })
            renderer.setSize(size.width, size.height)
            renderer.setClearColor(0x000000)
            renderer.setPixelRatio(window.devicePixelRatio)
            dom.appendChild(renderer.domElement)

            renderer.gammaFactor = 2
            renderer.gammaOutput = true
            renderer.shadowMap.enabled = true
        }
        var dom = document.querySelector('#output')
        init(dom)

        let controls

        let loader = new THREE.GLTFLoader().setPath( evirenment == 'dev' ? './model/': 'https://xiongtongzi.oss-cn-shanghai.aliyuncs.com/model/');
        THREE.DRACOLoader.setDecoderPath(  evirenment == 'dev' ? './model/': 'https://xiongtongzi.oss-cn-shanghai.aliyuncs.com/model/' );
        loader.setDRACOLoader( new THREE.DRACOLoader() )

        class LevelBlood{

            constructor(name, options){
                this.color = options.color || 0x0000ff // 血条颜色
                this.totalBlood = options.totalBlood|| 500// 总血量
                this.currentBlood = options.currentBlood || 500 //即时血量
                this.totalBlue = options.totalBlue|| 100// 总蓝量
                this.currentBlue = options.currentBlue || 100 //即时蓝量
                this.level = options.level || 1//初始等级
                this.bloodCellNumber = options.cellNumber || 100//单刻度值
                this.backgroundColor = options.backgroundColor || '#001'//整个背景色
                this.bloodColor = options.bloodColor || '#0f0' //血条颜色
                this.blueColor = options.blueColor || '#00f' //蓝条颜色
                this.totalInLevel = options.totalInLevel || 100 //级内总进度
                this.inLevel = options.inLevel || 0 //级内进度
                this.name = name

                this.init()
                this.draw()
            }

            init(){
                this.canvas = document.createElement('canvas')
                this.canvas.width = 512
                this.canvas.height = 128

                this.ctx = this.canvas.getContext('2d')
            }

            config(options){
                this.color = options.color || this.color// 血条颜色
                this.totalBlood = options.totalBlood|| this.totalBlood// 总血量
                this.currentBlood = options.currentBlood || this.currentBlood //即时血量
                this.totalBlue = options.totalBlue|| this.totalBlue// 总蓝量
                this.currentBlue = options.currentBlue || this.currentBlue //即时蓝量
                this.level = options.level || this.level//初始等级
                this.bloodCellNumber = options.cellNumber || this.bloodCellNumber//单刻度值
                this.backgroundColor = options.backgroundColor || this.backgroundColor//整个背景色
                this.bloodColor = options.bloodColor || this.bloodColor //血条颜色
                this.blueColor = options.blueColor || this.blueColor //蓝条颜色
                this.totalInLevel = options.totalInLevel || this.totalInLevel //级内总进度
                this.inLevel = options.inLevel || this.inLevel //级内进度
                
                this.draw()
            }

            draw(){
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)

                // 绘圆
                this.ctx.fillStyle = this.backgroundColor
                let halfHeight = this.canvas.height / 2
                let r = halfHeight * .8

                this.ctx.arc(halfHeight, halfHeight, r, 0, Math.PI * 2)
                this.ctx.fill()

                // 绘矩形
                let rectHeight = 50
                let marginTop = (this.canvas.height - rectHeight) * .5
                let marginBottom = (this.canvas.height + rectHeight) * .5

                this.ctx.fillStyle = this.backgroundColor
                this.ctx.beginPath()
                this.ctx.moveTo(halfHeight, marginTop)
                this.ctx.lineTo(this.canvas.width, marginTop)
                this.ctx.lineTo(this.canvas.width, marginBottom)
                this.ctx.lineTo(halfHeight, marginBottom)
                this.ctx.lineTo(halfHeight, marginTop)
                this.ctx.fill()
                this.ctx.closePath()

                //级内经验占位
                this.ctx.strokeStyle = '#000'
                this.ctx.lineWidth = 5
                this.ctx.beginPath()
                this.ctx.arc(halfHeight, halfHeight, r * 0.8, 0, Math.PI * 2)
                this.ctx.stroke()
                this.ctx.closePath()


                //级内经验
                this.ctx.strokeStyle = '#ff7f00'
                this.ctx.lineWidth = 5
                this.ctx.beginPath()
                this.ctx.arc(halfHeight, halfHeight, r * 0.8, - Math.PI * .5, this.inLevel / this.totalInLevel * Math.PI * 2 - Math.PI * .5)
                this.ctx.stroke()
                this.ctx.closePath()

                // 绘制等级
                this.ctx.font = 'bold 40px Arial'
                this.ctx.textAlign = 'center'
                this.ctx.fillStyle = '#fff'
                this.ctx.textBaseline ="middle"

                this.ctx.fillText(this.level, halfHeight, halfHeight)

                //绘制名称
                this.ctx.font = 'bold 40px Arial'
                this.ctx.textAlign = 'center'
                this.ctx.fillStyle = '#fff'
                this.ctx.textBaseline ="top"

                this.ctx.fillText(this.name, (this.canvas.width - this.canvas.height) * .5 + this.canvas.height, 0)

                let offsetY = 8
                let offsetX = 8
                let totalHeight = rectHeight - offsetY * 3
                let blueBloodStart = halfHeight + r
                let bloodBlueTotalLength = this.canvas.width - offsetX - blueBloodStart

                //绘制蓝条
                let blueCurrentLength = blueBloodStart + this.currentBlue / this.totalBlue * bloodBlueTotalLength
                this.ctx.fillStyle = this.blueColor
                this.ctx.beginPath()
                this.ctx.moveTo(blueBloodStart, marginBottom - totalHeight * .2 - offsetY)
                this.ctx.lineTo(blueCurrentLength, marginBottom - totalHeight * .2 - offsetY)
                this.ctx.lineTo(blueCurrentLength, marginBottom - offsetY)
                this.ctx.lineTo(blueBloodStart, marginBottom - offsetY)
                this.ctx.lineTo(blueBloodStart, marginBottom - totalHeight * .2 - offsetY)
                this.ctx.fill()
                this.ctx.closePath()

                //绘制血条
                let bloodCurrentLength = blueBloodStart + this.currentBlood / this.totalBlood * bloodBlueTotalLength
                this.ctx.fillStyle = this.bloodColor
                this.ctx.beginPath()
                this.ctx.moveTo(blueBloodStart, marginTop + offsetY)
                this.ctx.lineTo(bloodCurrentLength, marginTop + offsetY)
                this.ctx.lineTo(bloodCurrentLength, marginTop + totalHeight * .8 + offsetY)
                this.ctx.lineTo(blueBloodStart, marginTop + totalHeight * .8 + offsetY)
                this.ctx.lineTo(blueBloodStart, marginTop + offsetY)
                this.ctx.fill()
                this.ctx.closePath()

                //血量刻度
                this.ctx.strokeStyle = this.backgroundColor
                this.ctx.lineWidth = 6

                let splitNumber = this.totalBlood / this.bloodCellNumber
                let step = (this.canvas.width - offsetX - blueBloodStart) / splitNumber
                for(let i = 0; i < splitNumber; i ++){
                    let length = 12
                    if(i % 5 == 0){
                        length = 20
                    }
                    this.ctx.beginPath()
                    this.ctx.moveTo(blueBloodStart + i * step, marginTop + offsetY)
                    this.ctx.lineTo(blueBloodStart + i * step, marginTop + offsetY + length)
                    this.ctx.stroke()
                    this.ctx.closePath()
                }
            }

            test(id){// 测试输出用
                let dom = document.querySelector(id)
                dom.appendChild(this.canvas)
            }

        }
        
        var mixer, action;
        let ssxObject, ssxOriginRotation
        let clock = new THREE.Clock()
        let delta
        let sprite
        let levelBlood

        const speedNumber = evirenment == 'dev' ? 1 : 0.2
        let speed = new THREE.Vector2()


        //设置站立
        const setStand = () => {
            speed.set(0, 0)
            action && action.stop()
        }

        const go = (x, y) => {
            speed.set(x, y)
            action && action.play()
        }

        loader.load( 'model.gltf', function ( gltf ) {
            gltf.scene.rotation.x = Math.PI * .5
            gltf.scene.rotation.y = -Math.PI * .25

            gltf.scene.traverse((item) => {
                if(item.material){
                        item.material = new THREE.MeshBasicMaterial({map: item.material.map, transparent: true, alphaTest: 0.9})
                }

                if(item.children.length > 0 && (item.name.includes('地') || item.name.includes('路'))){
                    item.traverse((child) => {
                        child.receiveShadow = true
                    })
                }

            })

            scene.add(gltf.scene)

            let tl = new THREE.TextureLoader()
            tl.setPath( evirenment == 'dev' ? './model/': 'https://xiongtongzi.oss-cn-shanghai.aliyuncs.com/model/')
            loader.load('ssx.gltf', (ssx) => {
                ssx.scene.rotation.x = Math.PI * .5
                ssx.scene.rotation.y = Math.PI * 1.5

                ssxOriginRotation = ssx.scene.rotation.clone()

                ssx.scene.scale.set(4, 4, 4)
                ssx.scene.position.set(218.27291759843078, -4.683324102610722, 0)


                ssx.scene.traverse((obj) => {
                    if(obj.material){
                        let name = obj.name
                        obj.material.map = tl.load(name + '.png')

                        obj.castShadow = true
                    }
                })

                scene.add(ssx.scene)

                ssxObject = ssx.scene

                controls = new MOBAControls( camera, {
                    dom: renderer.domElement,
                    target: ssxObject
                })

                mixer = new THREE.AnimationMixer(ssx.scene)
                action = mixer.clipAction(ssx.animations[0])

                levelBlood = new LevelBlood(name + '', {inLevel: 49})
                levelBlood.test('#output')
                sprite = new THREE.Sprite(new THREE.SpriteMaterial({
                    map: new THREE.CanvasTexture(levelBlood.canvas),
                    transparent: true,
                    alphaTest: 0.6
                }))
                sprite.scale.set(8, 2, 1)
                scene.add(sprite)

                document.querySelector('#layer').style.display = 'none'

                let manager = nipplejs.create({
                    zone: dom,
                    multitouch: true,
                    maxNumberOfNipples: 1,
                    color: 'black'
                })

                let position = new THREE.Vector2()
                manager.on('start', (evt, data) => {
                    let {x, y} = data.position
                    position.set(x, y)
                })

                let pointerRaycaster = new THREE.Raycaster()
                manager.on('move', (evt, data) => {
                    let {x, y} = data.position

                    let offset = position.clone()
                    let length = offset.sub(new THREE.Vector2(x, y)).length()

                    // 限制最小响应
                    if(length < 20){
                        setStand()
                        return
                    }
                    if(data.angle){
                        let degree = data.angle.radian - Math.PI * .25
                        let {x, y, z} = ssxOriginRotation
                        ssxObject.rotation.set(x, y + degree, z)
                        go(- Math.cos(degree), - Math.sin(degree))

                        // let {x: posx, y: posy} = ssxObject.position

                        // // 射线判断
                        // pointerRaycaster.set(new THREE.Vector3(posx, posy, 1), new THREE.Vector3(- Math.cos(degree), - Math.sin(degree), 0).normalize())

                        // let raycasterGet = pointerRaycaster.intersectObjects(gltf.scene.children, true)
                        // // console.log(raycasterGet)
                        // if(raycasterGet.length > 0){
                        //     let one = raycasterGet[0]
                        //     if(one.distance < 1){
                        //         speed.set(0, 0)
                        //         console.log('停止')
                        //     }
                        // }
                    }else{
                        setStand()
                    }
                })

                manager.on('end', (evt, data) => {
                    setStand()
                    position.set(0, 0)
                }
                )
            })

        })

    //  nipple.js全面替代键盘操作
        // const keyDown = (e) => {
        //     e.preventDefault()
        //     let keyCode = e.keyCode
        //     if(!ssxObject) return
        //     if(keyCode == 87 || keyCode == 38){//w
        //         speed.y = -1
        //     }

        //     if(keyCode == 65 || keyCode == 37){//a
        //         speed.x = 1
        //     }

        //     if(keyCode == 83 || keyCode == 40){//s
        //         speed.y = 1
        //     }

        //     if(keyCode == 68 || keyCode == 39){//d
        //         speed.x = -1
        //     }
        // }

        // const keyUp = (e) => {
        //     e.preventDefault()
        //     let keyCode = e.keyCode
        //     if(!ssxObject) return
        //     if(keyCode == 87 || keyCode == 38){
        //         speed.y = 0
        //     }

        //     if(keyCode == 65 || keyCode == 37){
        //         speed.x = 0
        //     }

        //     if(keyCode == 83 || keyCode == 40){
        //         speed.y = 0
        //     }

        //     if(keyCode == 68 || keyCode == 39){
        //         speed.x = 0
        //     }
        // }
        const render = () => {
            controls && controls.update()
            delta = clock.getDelta()

            if(ssxObject){
                if(speed.length() > 0){
                    let {x, y} = speed.clone().normalize().multiplyScalar(speedNumber)
                    ssxObject.position.y += y
                    ssxObject.position.x += x
                    levelBlood.currentBlue > 0 && levelBlood.config({currentBlue: levelBlood.currentBlue - 0.2})
                    levelBlood.currentBlood > 0 && levelBlood.config({currentBlood: levelBlood.currentBlood - 0.1})
                }else{
                    levelBlood.currentBlue < levelBlood.totalBlue && levelBlood.config({currentBlue: levelBlood.currentBlue + 0.1})
                    levelBlood.currentBlood < levelBlood.totalBlood && levelBlood.config({currentBlood: levelBlood.currentBlood + 0.05})
                }

                sprite.material.map.image = levelBlood.canvas
                sprite.material.map.needsUpdate = true
            }
                

            sprite && sprite.position.copy(ssxObject.position).add(new THREE.Vector3(0, 0, 9))

            mixer && mixer.update( delta );

            renderer.render(scene, camera)
            requestAnimationFrame(render)
        }
        render()


        let mouse = new THREE.Vector2()
        let raycaster = new THREE.Raycaster()

        const move = (e) => {
            mouse.x = ((e.clientX - dom.getBoundingClientRect().left) / dom.offsetWidth) * 2 - 1
            mouse.y = -((e.clientY - dom.getBoundingClientRect().top) / dom.offsetHeight) * 2 + 1
            raycaster.setFromCamera( mouse, camera )

            let intersects = raycaster.intersectObjects(scene.children, true)
            if(intersects.length > 0){
                console.log(intersects[0])
            }
        }

        dom.addEventListener('click', move, false)

        const resize = () => {
            var size = {
                width: dom.offsetWidth,
                height: dom.offsetHeight
            }
            renderer.setSize(size.width, size.height)
            camera.aspect = size.width / size.height
            camera.updateProjectionMatrix()
        }

        window.addEventListener('resize', resize, false)

        // const FullScreen = () => {
        //     let isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen
        //     if(!isFullscreen){//进入全屏,多重短路表达式
        //         (document.requestFullscreen && document.requestFullscreen())||
        //         (document.mozRequestFullScreen && document.mozRequestFullScreen())||
        //         (document.webkitRequestFullscreen && document.webkitRequestFullscreen())||
        //         (document.msRequestFullscreen && document.msRequestFullscreen());
        //     }else{	//退出全屏,三目运算符
        //         document.exitFullscreen ? document.exitFullscreen():
        //         document.mozCancelFullScreen ? document.mozCancelFullScreen():
        //         document.webkitExitFullscreen ? document.webkitExitFullscreen():'';
        //     }
        // }
        const orientationchange = () => {
            if(window.innerHeight < window.innerWidth){
                console.log('full')
                // document.body.requestFullscreen && document.body.requestFullscreen()
            }else{
                console.log('exist')
                // document.exitFullscreen && document.exitFullscreen()
            }
            resize()
        }

        // window.addEventListener('orientationchange', orientationchange, false);


        // window.addEventListener('keydown', keyDown, false)
        // window.addEventListener('keyup', keyUp, false)
    }

</script>
</html>

代码片段不全

全部代码加我VX :lingyuwuhongyuan领取

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑I客I零

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值