面向对象02 - 案例:王者荣耀英雄选择

一、目标与说明

  1. 还是注重逻辑分析,图片素材为游戏截屏抠图而成,不涉及王者炫酷的动画效果。
  2. 运用面向对象的思想,在这里我会分析王者荣耀运用了哪些对象,然后抽离里面的功能和方法、抽离成类、研究每个类之间的逻辑关系、把每个类模块化。
  3. 最终实现进入登录界面完成登陆、选择英雄、选择皮肤、释放技能等一系列功能。
  4. 为什么要用面向对象来做?王者荣耀上百个英雄,每个英雄又对应各自的皮肤和技能。按照面向对象思想,根据项目的特点,把类与类之间的逻辑关系写好,实现模块化功能,到时候上百个英雄只需要直接对类进行实例化就可以完成功能,代码更加易于管理和高效。
  5. 实现功能并不难,怎么划分对象、怎么划分功能、搞清楚对象与对象之间的关系是关键点。

二、实现效果

王者荣耀英雄选择案例效果图

三、写之前先分析

  • 写之前先分析一波:假设我已经知道面向对象的思想、知道什么是对象、类、原型、继承等,现在有了这样一个需求,我该怎么把思维从面向过程转变为面向对象呢?
  • 可以按照以下步骤:
  1. 根据需求研究对象,比如我今天就写两个英雄,不需要研究一大堆东西,一切从需求出发就行。要考虑有哪些对象?对象有哪些属性和方法?有什么特性?
  2. 抽象成类,提升复用性。如果是一个类,它就不止一个对象,可能有成百上千个对象,抽离这些对象中的一些共性的东西成类。如果某个对象有特殊的功能的话,就没必要抽离成类。
  3. 上一步研究完对象的共性,已经抽离成类了,这一步可以根据需求研究类的共性问题,即抽离类成为基类(父类),这时候就可以考虑继承的问题。但是是根据需求来,如果需求简单,就没必要这么做。
  4. 研究类之间的逻辑关系,研究这个类需要那个类,这个类调用那个类等等。
  • 在王者荣耀这个案例中,我列出来的对象有:亚瑟、鲁班、玩家、技能、皮肤、游戏管理类game
  • 文件目录如下图:
    在这里插入图片描述

四、类

1. 玩家类

import Yase from './yase.js';
import Luban from './luban/js'
export default class Player{
    constructor(username){
        this.name = username;
        this.heroes = [new Yase,new Luban];
    }
}
  • 玩家就是用户,在这个案例中只涉及到了用户名和玩家拥有的英雄,所以只有两个属性name和heroes
  • 真正的游戏还有很多属性,例如等级啊、积分啊、钻石啊、点券等等
  • 这个界面引入了两个类,亚瑟类和鲁班类,是属于玩家的英雄,这里就可以显现面向对象的好处了,如果玩家还有其他英雄如李白,只需要引入李白类,并在heroes里面进行实例化即可。

2. 亚瑟类

//亚瑟类
import Hero from './hero.js'

import S1 from './skills/yase/s1.js'
import S2 from './skills/yase/s2.js'
import S3 from './skills/yase/s3.js'

import Skin1 from './skins/yase/skin1.js';
import Skin2 from './skins/yase/skin2.js';
import Skin3 from './skins/yase/skin3.js';

export default class Yase extends Hero{
    constructor(){
        let opts = {
            name: "亚瑟",
            ico: "./sources/heros/yase1.png",
            skills: [new S1(),new S2,new S3],
            skins: [new Skin1,new Skin2,new Skin3]
        }
        super(opts);
        // this.name = "亚瑟";
        // this.ico = "./sources/heros/yase1.png";
        // this.skills = [new S1(),new S2,new S3];
        // this.skins = [new Skin1,new Skin2,new Skin3];
    }
}
  • 亚瑟类包含四个属性,分别是英雄名、英雄图标、技能和皮肤
  • 技能被抽离成类,引入了三个技能S1,S2,S3,并实例化
  • 皮肤也被抽离成类,引入了三个皮肤Skin1,Skin2,Skin3,并实例化
  • 因为亚瑟、鲁班都是英雄,我在这里将亚瑟类和鲁班类的共性抽离成基类,即英雄类,所以这里引入了Hero类
  • 在这个案例中其实没必要抽离基类,下面注释是没有抽离的写法,是否抽离应该按实际需求来

3. 鲁班类

//鲁班类
import Hero from './hero.js'

import S1 from './skills/luban/s1.js'
import S2 from './skills/luban/s2.js'
import S3 from './skills/luban/s3.js'

import Skin1 from './skins/luban/skin1.js'
import Skin2 from './skins/luban/skin2.js'
import Skin3 from './skins/luban/skin3.js'

export default class Luban extends Hero{
    constructor(){
        let opts = {
            name : "鲁班",
            ico : "./sources/heros/luban1.png",
            skills : [new S1(),new S2(),new S3()],
            skins : [new Skin1,new Skin2, new Skin3],
        }
        super(opts);
    }
}
  • 说明和亚瑟类相似,这里不赘述

4.英雄基类

// 英雄基类;
import GameEvent from './GameEvent.js';
export default class  Hero extends GameEvent{
    constructor({name,ico,skills,skins}){
        super();
        this.name = name;
        this.ico = ico;
        this.skills = skills;
        this.skins = skins;
        // 绑定自定义事件
        this.addEvent("myinit",this.init);
    }
    init(){
        console.log("初始化了");
    }
}
  • 抽离出一些英雄的共性,例如name、ico、skills、skins
  • 进行了一个初始化实现(功能很简单哈哈哈,只打印了一下初始化了)
  • 这里的addEvent方法是继承的父类GameEvent里面的添加事件的方法
  • 父类GameEvent就是用来管理一些事件的添加移除的,这里不过多赘述,详细代码可以下载源码查看

5. 技能类和皮肤类

在这里插入图片描述

  • 逻辑比较简单我就以图片形式呈现啦
  • 技能类包含了两个属性 name 和 ico,以及一个释放技能 release 方法
  • 皮肤类就简简单单包含了三个属性 name 、ico、 img;注意,ico是小图标;img是大图片

6. 总结

  1. 类与类之间的关系就说到这里啦,看似抽离了这么多类很麻烦,但其实一旦英雄数量多起来,玩家多起来,就会显现出这样做的好处,逻辑更清晰、更易于管理,哪里出现了bug也可以第一时间发现
  2. 所以大家还是慢慢学会转变自己的思想,从面向过程到面向对象

五、页面结构和逻辑

1. 页面元素

<body>
    <!-- 登录页面 -->
    <div class="login">
        <input class="username" /> <button class="sub">登录</button>
        <img src="./sources/login.JPG" alt="">
    </div>
    <!-- 游戏选择页面 -->
    <div class="game">
        <button class="heroBtn">英雄</button>
        <div class="heroContainer">
            <div class="heroView">
                <div class="heroItem">
                    <img src="./sources/heros/yase1.png" />
                    <span>亚瑟</span>
                </div>
                <div class="heroItem">
                    <img src="./sources/heros/yase1.png" />
                    <span>亚瑟</span>
                </div>
            </div>
        </div>
       
        <button class="skinBtn">皮肤</button>
        <div class="skinContainer">
            <div class="skinView">
                <!-- <div class="skinItem">
                    <img src="./sources/heros/yase1.png" />
                    <span>经典</span>
                </div>
                <div class="skinItem">
                    <img src="./sources/heros/yase2.png" />
                    <span>死亡骑士</span>
                </div> -->
            </div>
        </div>
        
        <div class="skinShow">
            <img src="./sources/skins/301660.png" alt="">
        </div>
        <div class="userView">
            <div class="heroShow">
                <!-- <img src="./sources/heros/yase1.png" /> -->
            </div>
            <span class="chioseusername">张三</span>
        </div>
       
        <div class="skillsView">
            <!-- <img src="./sources/skills/11210.png" />
            <img src="./sources/skills/11220.png" />
            <img src="./sources/skills/11230.png" /> -->
        </div>
        <div>

        </div>
        <img src="./sources/chiose.JPG" />
    </div>
    <script type="module" src="./index.js"></script>
</body>
  • 主要是一些 div 结构,注意 class 类名要起的很规范,这样写逻辑操作DOM结构的时候才不会乱套
  • 代码倒数第二行采用模块化思想,导入 index.js 业务逻辑

2. Style样式

    <style>
        body {
            margin: 0;
            padding: 0;
        }

        .username {
            position: absolute;
            left: 347px;
            top: 250px;
            border-radius: 5px;
            height: 24px;
        }

        button {
            background: transparent;
            outline: none;
            border: none;
            color: white;
        }
        .heroShow{
            width: 50px;
            height: 50px;
        }
        .sub {
            position: absolute;
            left: 351px;
            top: 288px;
            width: 126px;
            color: white;
            font-weight: bold;
            font-size: 18px;
        }
        .geme {
            position: relative;
        }

        .heroBtn {
            position: absolute;
            left: 45px;
            top: 8px;
            font-size: 14px;
        }
        .skinBtn {
            position: absolute;
            top: 8px;
            left: 105px;
            font-size: 14px;
        }
        .userView{
            position: absolute;
            /* width: 80px; */
            top: 34px;
            left: 720px;
        }
        .userView img{
            width: 40px;
            height: 40px;
        }
        .chioseusername {
            display: block;
            color: rgb(255, 215, 0);
            text-align: center;
             font-size: 12px;
            font-weight: bold;
        }

        .skillsView {
            position: absolute;
            display: flex;
            flex-direction: column;
            left: 660px;
            top: 200px;
        }

        .skillsView img {
            width: 40px;
            height: 40px;
            margin-bottom: 10px;
        }
        .heroView{
            width: 120px;
            position:absolute;
            margin-top: 40px;
            margin-left: 20px;
            display: flex;
            flex-wrap: wrap;
        }
        .skinView{
            width: 130px;
            position:absolute;
            margin-top: 40px;
            margin-left: 20px;
            display: flex;
            flex-wrap: wrap;
        }
        .heroView img {
            width: 50px;
            height: 50px;
            
        }
        .skinView img{
            width: 50px;
            height: 50px;
        }
        .heroItem{
            margin-left: 10px;
            margin-top: 10px;
            display: flex;
            flex-direction: column;
            color: gray;
            align-items: center;
            font-size: 12px;
        }
        .skinItem{
            margin-left: 10px;
            margin-top: 10px;
            display: flex;
            flex-direction: column;
            color: gray;
            align-items: center;
            font-size: 12px;
        }
        .skinShow{
            position:absolute;
            left:320px;
            top: 40px;
        }
        .login {
            display: block;
        }
        .game{
            display: none;
        }
        .heroContainer{
            display: block;
        }
        .skinContainer{
            display: none;
        }
    </style>
  • 我这里直接写进 style 标签里了,其实更好的做法应该是写css文件,然后引入进来

3. 逻辑操作

import Game from './game/game.js';

// 对象: 鲁班、亚瑟、玩家、技能、游戏管理类;

let game = new Game();

function decorator(fn1,fn2,skill,...arg){
    fn1.call(skill);
    fn2(...arg);
}

function hurt(num){
    console.log("造成"+num+"点伤害");
}

document.querySelector(".sub").onclick = function(){
    let username = document.querySelector(".username").value;
    // console.log(username);
    game.login(username);
    console.log(game);
    // 隐藏login 显示选择;
    document.querySelector(".login").style.display = "none";
    document.querySelector(".game").style.display = "block";
    // 修改名称
    document.querySelector(".chioseusername").innerHTML = username;
    renderHeroes(game.player.heroes);
}

function renderHeroes(heroes){
    console.log(heroes);
    document.querySelector(".heroView").innerHTML = "";
    heroes.forEach(hero=>{
      let heroItem =   document.createElement("div");
      heroItem.classList.add("heroItem");
      heroItem.innerHTML = `<img src="${hero.ico}" />
      <span>${hero.name}</span>`;
      document.querySelector(".heroView").appendChild(heroItem);
      heroItem.onclick = function(){
          document.querySelector(".heroShow").innerHTML = `<img src="${hero.ico}" />`
        //  渲染技能
        renderSkills(hero.skills);
        
        // 渲染皮肤;
        renderSkins(hero.skins);
      }
    })
}

function renderSkills(skills){
    document.querySelector(".skillsView").innerHTML = "";
    skills.forEach(skill=>{
        let img = document.createElement("img");
        img.src = skill.ico;
        document.querySelector(".skillsView").appendChild(img);
        img.onclick = function(){
            decorator(skill.release,hurt,skill,100);
        }
    })
}

// 渲染皮肤
function renderSkins(skins){
    document.querySelector(".skinView").innerHTML="";
    document.querySelector(".skinShow").innerHTML = `<img src="${skins[0].img}" />`;
    skins.forEach(skin=>{
        let skinDiv = document.createElement("div");
        skinDiv.classList.add("skinItem");
        skinDiv.innerHTML = `<img src="${skin.ico}" />
        <span>${skin.name}</span>`;
        document.querySelector(".skinView").appendChild(skinDiv);
        skinDiv.onclick = function(){
            document.querySelector(".skinShow").innerHTML = `<img src="${skin.img}" />`;
        }
    })

}

// 切换 英雄 及皮肤;
document.querySelector(".heroBtn").onclick = function(){
    document.querySelector(".heroContainer").style.display = "block";
    document.querySelector(".skinContainer").style.display = "none";
}

document.querySelector(".skinBtn").onclick = function(){
    document.querySelector(".heroContainer").style.display = "none";
    document.querySelector(".skinContainer").style.display = "block";
}
  • 是按照之前讲的数据驱动的思想,所以这里一般都放一些渲染视图的逻辑。
  • 具体都是一些DOM结构的基本操作,如果使用 vue 或者 react 开发的话,这些逻辑将会更简单。

六、 总结

  1. 这个案例能很好的体现面向对象的思想。其实无论是面向对象还是面向过程都有一定的好处,只是要根据实际需求来定。
  2. 巩固自己的同时也希望可以帮到大家~
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: HTML可以实现模拟王者荣耀选择英雄的效果。首先,我们可以使用HTML的表单元素创建一个英雄选择的界面。在这个界面上,我们可以使用下拉框来显示可供选择英雄列表。下拉框可以使用HTML的`<select>`元素来创建,每个英雄可以使用`<option>`元素来表示。同时,我们可以通过设置每个`<option>`元素的值来标识对应的英雄。例如,可以将英雄的名字作为`<option>`元素的值。 然后,我们可以通过使用HTML的`<button>`元素来添加一个“确认选择”按钮。当玩家选择英雄之后,可以点击这个按钮来确认选择。 接下来,我们可以使用JavaScript来实现选择英雄后的操作。当点击“确认选择”按钮时,JavaScript可以监听到这个点击事件,并且获取到玩家选择英雄的值(即英雄的名字)。然后,JavaScript可以根据这个值执行相应的操作,例如显示英雄的详细信息、切换到相应的游戏画面等。 总结起来,使用HTML的表单元素和JavaScript的事件监听,我们可以实现一个基本的HTML模拟王者荣耀选择英雄的界面和操作。当玩家通过下拉框选择英雄后,点击“确认选择”按钮,JavaScript可以根据选择英雄执行相应操作,实现模拟王者荣耀选择英雄的效果。 ### 回答2: 要实现HTML模拟王者荣耀选择英雄,我们可以使用HTML、CSS和JavaScript来创建一个交互式的界面。 首先,我们可以使用HTML来创建一个包含所有英雄选择列表。使用<select>标签可以创建一个下拉菜单,每个选项都代表一个英雄。例如: ```html <select id="hero-select"> <option value="1">鲁班七号</option> <option value="2">孙悟空</option> <option value="3">花木兰</option> <option value="4">貂蝉</option> <!-- 其他英雄选项 --> </select> ``` 然后,我们可以使用JavaScript来实现选择英雄的功能。我们可以通过监听下拉菜单的change事件来获取选择英雄的值,并根据该值进行相应的处理。例如: ```javascript document.getElementById("hero-select").addEventListener("change", function() { var selectedHero = this.value; // 根据选择英雄值做相应的处理 switch(selectedHero) { case "1": // 鲁班七号的处理 break; case "2": // 孙悟空的处理 break; case "3": // 花木兰的处理 break; case "4": // 貂蝉的处理 break; // 其他英雄的处理 } }); ``` 最后,我们可以使用CSS来美化界面,使其看起来更像王者荣耀的风格。可以为下拉菜单和英雄进行相应的样式设置。 通过上述步骤,我们可以创建一个基本的HTML模拟王者荣耀选择英雄的界面,用户可以通过下拉菜单选择英雄,然后根据选择英雄进行相应的处理。当然,还可以通过进一步完善,加入更多交互和功能,使其更加逼真和有趣。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值