前言
同学们前面已经学习了html css javascript基础部分了,为了巩固和熟练前面所学的知识,从今天起,我们要做一个捕虫游戏的项目。通过项目实战夯实基础,将所学的知识真正用到实战中,强化对网页设计的能力,体验使用vscode进行网页编程。
单元一 捕虫游戏制作
任务1.1创建捕虫游戏文件
任务描述
主要实现的是项目文件夹的创建。
任务实施
首先我们先新建一个本地文件夹捕虫游戏如下图:
在vscode中打开这个文件夹,以后的捕虫游戏的项目就在这个文件夹中进行。
再新建的文件夹中,再次创建一个新文件夹用来放置源代码文件。该文件夹中应包含三个文件分别为html文件、css文件、js文件、img图片包。如下图:
任务2.1 项目制作
任务目标
学生能够自己完成写一个捕虫游戏的项目网站。
任务描述
本任务主要分为三个部分,先是搭建一个html框架,第二部分是将搭建好的html进行css部分。最后进行js部分的完成实现相应功能。
主要功能:
- 进入页面之后点击“玩游戏”,进到玩游戏的界面
- 开始选择对应昆虫,选择完昆虫之后即进入游戏界面开始游戏
- 左上角计时器即刻开始计时
- 最开始在页面上随机生成一只昆虫,点击对应昆虫后页面上会随机存在两只昆虫。以此类推成递增趋势。
- 同时右上角分数记录当前消灭昆虫数量。
- 当达到一定分数时会出现一个弹窗,提示用户这是一个不可能完成的游戏。
任务分析
该案例主要可以分为三个页面,分别是刚进入网页时的页面,选择昆虫页面,开始游戏页面。在这里大家可以有很多思路来实现这个网页,可以是创建三个不同的html文件,点击相应按钮即可跳转对应界面,也可以在一个html文件中对其设置不同盒子相同类名,在JS中分别进行显示,但在本文档里用的都不是以上方法。在这里是使用了display:none以及display:block通过这两个方法来实现的,
大体思路是,在本个页面分别把这几个框架全部做出来,并用相对定位或绝对定位的方法进行定位。然后在CSS中display属性设置为none再通过JS中识别点击事件把相应的页面样式设置为none或block;
任务2.2 HTML框架部分
页面分析
对其任务进行分析完毕之后,可以开始对HTML页面进行搭建,我们可以在body中新建三个大盒子每个大盒子中放入相应的几个页面。在对其页面内容进行搭建
任务实施
注意:我们要把之后需要使用的标签进行设置类名和id注意类名规范
2.2.1首页
首页部分很简单就是两个简单的标签一个<h1>标签和一个<button>按钮。
<div class="container">
<h1>捕捉昆虫</h1>
<button class="btn" id="playbtn">玩游戏</button>
</div>
2.2.2选择昆虫
选择昆虫这个页面可以看成是上下两个大盒子上面是一行文本用<h1>写入,
下面是一个大盒子里面包含了四个昆虫图片以及昆虫名,分别放入这四个昆虫的可以是一个<button>按钮,也可以是一个<div>。本文档使用的是<div>容器。
每个小盒子里新建一个<p>标签用来写入昆虫名,然后是一个<img>放入昆虫图片。注意每个图片的路径确定正确。
<div class="container1">
<h1>你最“喜欢”的昆虫是什么?</h1>
<div class="bigchoose">
<div class="choose" id="cy">
<p id="cy">苍蝇</p><img src="img/cangying.png" alt="" id="cy">
</div>
<div class="choose" id="wenzi">
<p id="wenzi">蚊子</p><img src="img/wenzi.png" alt="" id="wenzi">
</div>
<div class="choose" id="spider">
<p id="spider">蜘蛛</p><img src="img/spider.png" alt="" id="spider">
</div>
<div class="choose" id="zl">
<p id="zl">蟑螂</p><img src="img/zhanglang.png" alt="" id="zl">
</div>
</div>
</div>
2.2.3开始游戏
这个部分运行结果看着挺多,但其实只需要一个左上角的计时器,和一个右上角的分数计分器。其余的昆虫部分都是在JS中实现的。
所以在这个大盒子中只需要创建4个<h1>标签分别写入文本。
<div class="container2">
<h1 class="time">游戏时间:</h1>
<h1 id="time">00:00</h1>
</h1>
<h1 class="score">
<h1 id="score">0</h1>
</h1>
</div>
2.2.4提示页面
当分数达到一定的分数时会出现一个提示条,我们可以在最后新建一个盒子,里面放入一个<h2>标签写入提示文本。
<div class="hei">
<h2>嘿嘿,你会发现这是个不可能完成的游戏,不过你还是
可以试试看!
</h2>
</div>
任务2.3 CSS基本样式
任务目标
对新建的html框架进行页面美化。
任务实施
2.3.1首页样式
在设置首页样式之前避免浏览器的默认样式影响布局。先进行全局样式重置,然后我们会发现全局的背景颜色都是一个蓝色,并且所有的盒子都在<body>中,所以也要先进行主体样式的设置。
* {
margin: 0;
padding: 0;
}
body {
background-color: rgb(81, 109, 255);
color: white;
text-align: center;
overflow: hidden;
user-select: none;
}
- 全局样式重置:* { margin: 0; padding: 0; } 这部分代码会将所有元素的默认外边距和内边距都设置为0,以避免浏览器的默认样式影响布局。
- 主体样式:body样式设置了背景颜色为蓝色,并将文字颜色设为白色,以及居中对齐,同时禁用了文本选择功能并隐藏了溢出内容。
接下来开始首页样式的设置
- .container类使用Flexbox布局,使其内容在垂直和水平方向上居中,并通过设置顶部外边距来调整位置。
- 按钮样式:.btn类设置了按钮的宽度、高度,去掉边框,设定文字颜色。:hover伪类用来增加按钮在鼠标悬停时的透明度,这使得按钮在悬停时稍微变暗点。
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 400px;
}
.btn {
border: none;
width: 80px;
height: 50px;
color: rgb(88, 88, 241);
}
.btn:hover {
opacity: 0.9;
}
2.3.2选择昆虫页面样式
.container1 {
position: absolute;
top: 40%;
left: 32%;
display: none;
}
.bigchoose {
display: flex;
}
.choose {
width: 155px;
height: 155px;
border: 3px solid white;
margin: 10px;
}
.choose:hover {
background-color: white;
color: rgb(88, 88, 241);
;
}
.choose img {
width: 100px;
height: 100px;
}
- .container1:
设置了position: absolute;,使其绝对定位在页面上。
通过top: 40%;和left: 32%;来调整其位置。
display: none; 表示该容器初始状态下是隐藏的。
- .bigchoose:
使用display: flex;来将其子元素以Flexbox布局排列,这样可以方便地控制子元素的对齐和间距。
- .choose:
设置了宽度和高度为155px,并且使用白色边框和10px的外边距,使选择项之间有一定的距离。
- .choose:hover:
在鼠标悬停时,背景颜色变为白色,文字颜色变为蓝色。
- .choose img:
容器内的图片宽度和高度都设置为100px,确保选择项中的图片以统一的大小显示。
2.3.4开始游戏界面样式
.container2 {
display: none;
}
.container2 .time {
position: absolute;
top: 0;
left: 20px;
}
#time {
position: absolute;
top: 0;
left: 170px;
}
.score {
position: absolute;
top: 0;
right: 120px;
}
#score {
position: absolute;
top: 0;
right: 20px;
}
- .container2:
display: none; 表示该容器默认是隐藏的,在如游戏开始时才会显示。
- .container2 .time:
该选择器设置了时间显示的位置。
position: absolute;使其可以根据其父容器的位置进行绝对定位。
top: 0;和left: 20px;定义了时间标签在容器内的具体位置。
- #time:
这个同样使用绝对定位。
top: 0;和left: 170px;指定了时间文本的具体位置。
- .score:
和时间显示类似,分数的类选择器使用绝对定位。
top: 0; 和 right: 120px;指明了得分的位置
- #score:
这个ID选择器用于具体得分的显示,使用绝对定位.
2.3.5新增节点/类、提示框的样式
在我们后续的JS部分中会创建一些新的节点,主要是用来在开始游戏的时候,
例如对于我们新生成的昆虫的样式,点击昆虫时的样式等等。
若这部分不懂可以在我们编辑完JS部分之后在进行对其CSS样式的编辑。
.random {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 100px;
height: 100px;
position: absolute;
transform: translate(-50%, -50%) scale(1);
transition: transform 0.3s ease-in-out;
}
.random.caught {
transform: translate(-50%, -50%) scale(0);
}
.random img {
width: 100px;
height: 100px;
}
.hei{
width: 100%;
height: 100px;
background-color: rgba(0, 0, 0, 0.552);
line-height: 100px;
position: absolute;
top: 300px;
display: none;
}
- transform: translate(-50%, -50%) scale(1);:首先将元素偏移自身宽高的50%,然后将其缩放为原始大小(1倍)。
- transition: transform 0.3s ease-in-out;:设置变换的过渡效果,使变换更加平滑,持续时间为 0.3 秒。
- .random.caught:
该类选择器通过transform: translate(-50%, -50%) scale(0);实现了一个缩放效果,使得被捕到的昆虫在页面上缩小到0,使昆虫消失。
- .random img:
这个选择器用于设置随机昆虫的图片大小,宽度和高度均为100px,确保图片在界面中保持一致的显示效果。
- .hei:
这个类用于定义一个100px高的黑色半透明背景区域,
- line-height: 100px; 是用来将文本垂直居中。
- 使用position: absolute;和top: 300px;将这个区域放置在页面的绝对位置。
display: none;表示该区域在默认情况下是隐藏的,当分数到达一定值时就会显示出来。
任务2.4 JS功能实现部分
任务目标
实现按钮,选昆虫,计时器,计分器,昆虫递增随机出现,提示框的显示等功能。
任务实施
1.实现“玩游戏”按钮功能
先通过document.querySelector和document.getElementById获取元素
const playbtn = document.getElementById('playbtn');
const container1 = document.querySelector('.container1');
const container = document.querySelector('.container');
然后为playbtn按钮添加点击事件的监听器,当按钮被点击时,会执行内部的函数。在点击事件的回调函数中,container.style.display = 'none';表示将主容器(游戏开始界面)隐藏。
container1.style.display = 'block';表示显示container1(用于选择昆虫的界面)。
playbtn.addEventListener('click', function () {
container.style.display = 'none';
container1.style.display = 'block';
});
2.选择昆虫功能
目前是能够点击“玩游戏”进入为选择昆虫的界面。
由于从这到后面结束都会有很强的关联性和逻辑性所以我可们可以先把后续会用到的所有元素都获取上。
const bigchoose = document.querySelector('.bigchoose');
const cangying = document.getElementById('cy');
const wenzi = document.getElementById('wenzi');
const spider = document.getElementById('spider');
const zhanglang = document.getElementById('zl');
const container2 = document.querySelector('.container2');
const time = document.getElementById('time');
const score = document.getElementById('score');
此时开始选择昆虫的部分,还是像前面那样我们要当点击昆虫时要让当前页面隐藏,使玩游戏的页面展示出来。
container2.style.display = 'block';
container1.style.display = 'none';
看结果图可知我们最后是有种昆虫可以选择的,所以我们的监听器应该是4个小盒子的父元素,让父元素进行监听,我们知道当玩家选择完对应昆虫后的开始游戏生成的昆虫是跟玩家所选择的昆虫是对应的,所以,我们应该如何让监听器知道我们选择的是哪个昆虫,并让后期的开始游戏部分生成玩家所选择的昆虫呢?
我们可以在html中为每个与昆虫相关的标签都赋予不同的id名,通过判断点击事件的目标元素e.target.id,来获取我们所点击的对应昆虫。
let selectedImage;
bigchoose.addEventListener('click', function (e) {
container2.style.display = 'block';
container1.style.display = 'none';
startTimer();
if (e.target.id === 'cy') {
selectedImage = imgsrc.cangying;
} else if (e.target.id === 'wenzi') {
selectedImage = imgsrc.wenzi;
} else if (e.target.id === 'spider') {
selectedImage = imgsrc.spider;
} else if (e.target.id === 'zl') {
selectedImage = imgsrc.zhanglang;
}
createRandom();
})
我们最终的能运行都是依靠着这个监听器事件的。
- startTimer();为计时器的函数
- createRandom();为随机生成昆虫的函数
- let selectedImage;以及selectedImage = imgsrc.cangying;,为后续的生成昆虫提供对应的图片路径。
3.计时器功能
let timer;
let seconds = 0;
function startTimer() {
seconds = 0;
timer = setInterval(function () {
seconds++;
const minutes = Math.floor(seconds / 60);
const secs = seconds % 60;
time.innerText =
(minutes < 10 ? '0' + minutes : minutes) + ':' +
(secs < 10 ? '0' + secs : secs);
}, 1000);
}
- let timer;:声明一个变量timer,用于存储定时器的ID。
- let seconds = 0;:声明一个变量seconds,用于记录经过的秒数,初始值为0
- 使用setInterval方法每1000毫秒(1秒)执行一次内部的函数,用于更新计时。
- seconds = 0; 在每次调用startTimer时,将seconds重置为0,以确保计时从头开始。
- seconds++表示每秒钟将seconds加1。
- Math.floor(seconds / 60)计算出当前的分钟数,seconds % 60得到当前的秒数。
- time.innerText = ...;用来更新页面上用于显示时间的元素内容
- 格式:(minutes < 10 ? '0' + minutes : minutes) + ':' +(secs < 10 ? '0' + secs : secs);
格式为“MM:SS”。如果分钟或秒数小于10,则在前面加0以保持格式统一。
4.生成随机昆虫函数
首先定义一个createRandom函数,在这个函数中大体想实现的内容就是创建一个新节点用于放置随机生成的昆虫,选择想将新建节点插入到指定位置的元素。
进行样式设置,然后再设置随机昆虫的随机出现位置,为生成的虫子添加点击事件再点击事件中在添加消灭虫子,再次递增生成昆虫,计分器等函数。
function createRandom() {
const newdiv = document.createElement('div');
const body = document.querySelector('body');
newdiv.classList.add('random');
const { x, y } = Randomadress();
newdiv.style.left = x + 'px';
newdiv.style.top = y + 'px';
newdiv.innerHTML = `<img src="${selectedImage}" alt="" style="transform: rotate(${Math.random() * 360}deg)"/>`;
newdiv.addEventListener('click', function () {
jiaScore();
this.classList.add('caught')
setTimeout(() => this.remove(), 2000)
adddiv();
})
body.appendChild(newdiv);
}
- 创建一个新的div元素,名为newdiv。选择页面的body元素,以便在其中添加新创建的div。
- newdiv.classList.add('random');:为新创建的div添加random类,以便应用相应的CSS样式。
- const { x, y } = Randomadress();:调用Randomadress函数以获取一个随机的坐标(x和y),用于定位新元素。再根据随机生成的坐标设置新元素的具体位置。
- 向新盒子添加昆虫并设置路径和随机旋转角度style="transform: rotate(${Math.random() * 360}deg)"
- 添加生成的昆虫点击事件,包括计分,递增生成,捕获昆虫,删除昆虫等
- body.appendChild(newdiv);:将新创建的div元素添加到body中,以使其在页面上可见。
5.生成昆虫的图片路径问题
基本大函数已经写完,现在来解决,我们如何做到玩家点击哪个昆虫我们就会在开始游戏的时候生成相应昆虫。
在前面我们也提到过我们通过e.target.id这个方法已经能够获取到相应id,现在只需要将该id对应的路径给在刚刚的
newdiv.innerHTML = `<img src="${selectedImage}" alt="" style="transform: rotate(${Math.random() * 360}deg)"/>`;中。
我们可以通过新建一个字典来实现,对字典进行键值对的赋值。
const imgsrc = {
cangying: './img/cangying.png',
wenzi: './img/wenzi.png',
spider: './img/spider.png',
zhanglang: './img/zhanglang.png',
};
然后新建一个变量
let selectedImage;
再将获取到id对应的值赋值给selectedImage;再放进img src="${selectedImage}"中,例如:
if (e.target.id === 'cy') {
selectedImage = imgsrc.cangying;
此时<img src="${selectedImage}"中selectedImage的值就为字典中所对应的'./img/cangying.png'
此时我们新建的昆虫对应图片就可以和玩家所选择的昆虫对应上。
6.生成的随机位置函数
该函数用于我们的昆虫图片生成的时候会生成随机坐标。
function Randomadress() {
const width = innerWidth;
const height = innerHeight;
const x = Math.random() * width;
const y = Math.random() * height;
return { x, y }
}
- 获取窗口尺寸
const width = innerWidth;:获取当前浏览器窗口的宽度。
const height = innerHeight;:获取当前浏览器窗口的高度。
代表在此宽度中生成随机坐标。
- 生成随机坐标:
const x = Math.random() * width;:通过Math.random()函数生成一个范围在0到width之间的随机数,作为横坐标x。
const y = Math.random() * height;:同样,生成一个范围在0到height之间的随机数,作为纵坐标y。
- 返回坐标对象
最后使用return { x, y }:将生成的坐标以对象的形式返回,包含x和y属性。
再回到前面我们会将返回的坐标,放在创建随机昆虫的函数里并调用该函数,
7.点击随机昆虫函数
在创建完随机昆虫的函数中,还需要一个函数用来实现,点击昆虫会使昆虫消失,并递增生成新的昆虫,和点击昆虫的同时,计分器也会跟着记录杀掉的昆虫数,
newdiv.addEventListener('click', function () {
jiaScore();
this.classList.add('caught')
setTimeout(() => this.remove(), 2000)
adddiv();
})
还是需要先为新创建的div(目标)添加一个点击事件的监听器。
- jiaScore();:调用jiaScore函数,即为计分器函数。
- this.classList.add('caught');:为当前被点击的元素添加caught类,该代码就是在CSS中对于消灭掉的昆虫进行一个动画处理。
- 设置延时移除元素:使用setTimeout设置一个2秒的延时,在2秒后移除当前元素。
- adddiv();则为在当前昆虫被捕获后生成下一个新的昆虫,使得游戏能够持续进行。
8.计分器函数
let scoreNum = 0;
function jiaScore() {
scoreNum++;
score.innerHTML = `分数: ${scoreNum}`
if (scoreNum >= 20) {
hei=document.querySelector('.hei');
hei.style.display='block';
}
}
首先声明一个变量scoreNum,用于记录当前得分,初始值设为0。
scoreNum++;:每次调用该函数时,将得分scoreNum增加1。
score.innerHTML = 分数: ${scoreNum};:更新页面中显示得分的元素内容,表示在游戏界面中显示当前分数。
这里的if语句就是对应了在前面所说过的当分数达到一定条件时会出现一个提示框,我们就在这里进行设置。
使用if (scoreNum >= 20) :用来检查当前得分是否达到了20分的条件。
再获取一下当前提示框元素,如果得分达到20分,设置该元素的display样式为block,从而使其在页面上显示。
9.生成新昆虫元素
由案例功能条件可知,我们新增的昆虫是在杀死一只过后会递增的所以我们要使用该函数来达到其目的。
function adddiv() {
setTimeout(createRandom, 1000)
setTimeout(createRandom, 1500)
}
setTimeout(createRandom, 1000):使用setTimeout方法,在1秒后调用createRandom函数,以生成一个新的随机昆虫。
下面的1500毫秒同理。这样每次调用adddiv函数时,游戏会在1秒和1.5秒后分别生成两个新目标。而且在setTimeout方法中调用的是创建随机昆虫的函数,使其成为一个循环发生的事件。这样玩家可以在游戏过程中不断有新的昆虫出现。
10.整合
到此为止关于我们的JS部分代码全部完成,进行最后的整合阶段。
JS全部代码:
const playbtn = document.getElementById('playbtn');
const container1 = document.querySelector('.container1');
const container = document.querySelector('.container');
playbtn.addEventListener('click', function () {
container.style.display = 'none';
container1.style.display = 'block';
});
const bigchoose = document.querySelector('.bigchoose');
const cangying = document.getElementById('cy');
const wenzi = document.getElementById('wenzi');
const spider = document.getElementById('spider');
const zhanglang = document.getElementById('zl');
const container2 = document.querySelector('.container2');
const time = document.getElementById('time');
const score = document.getElementById('score');
let timer;
let seconds = 0;
function startTimer() {
seconds = 0;
timer = setInterval(function () {
seconds++;
const minutes = Math.floor(seconds / 60);
const secs = seconds % 60;
time.innerText =
(minutes < 10 ? '0' + minutes : minutes) + ':' +
(secs < 10 ? '0' + secs : secs);
}, 1000);
}
const imgsrc = {
cangying: './img/cangying.png',
wenzi: './img/wenzi.png',
spider: './img/spider.png',
zhanglang: './img/zhanglang.png',
};
let selectedImage;
bigchoose.addEventListener('click', function (e) {
container2.style.display = 'block';
container1.style.display = 'none';
startTimer();
if (e.target.id === 'cy') {
selectedImage = imgsrc.cangying;
} else if (e.target.id === 'wenzi') {
selectedImage = imgsrc.wenzi;
} else if (e.target.id === 'spider') {
selectedImage = imgsrc.spider;
} else if (e.target.id === 'zl') {
selectedImage = imgsrc.zhanglang;
}
createRandom();
})
function createRandom() {
const newdiv = document.createElement('div');
const body = document.querySelector('body');
newdiv.classList.add('random');
const { x, y } = Randomadress();
newdiv.style.left = x + 'px';
newdiv.style.top = y + 'px';
newdiv.innerHTML = `<img src="${selectedImage}" alt="" style="transform: rotate(${Math.random() * 360}deg)"/>`;
newdiv.addEventListener('click', function () {
jiaScore();
this.classList.add('caught')
setTimeout(() => this.remove(), 2000)
adddiv();
})
body.appendChild(newdiv);
}
function Randomadress() {
const width = innerWidth;
const height = innerHeight;
const x = Math.random() * width;
const y = Math.random() * height;
return { x, y }
}
let scoreNum = 0;
function jiaScore() {
scoreNum++;
score.innerHTML = `分数: ${scoreNum}`
if (scoreNum >= 20) {
hei=document.querySelector('.hei');
hei.style.display='block';
}
}
function adddiv() {
setTimeout(createRandom, 1000)
setTimeout(createRandom, 1500)
}
任务2.5 对该项目进行整合
全部代码编辑完成之后在html中进行引用。
<link rel="stylesheet" href="bc.css">
<body>………..</body>
<script src="bc.js"></script>
注意引用位置!!!