来来来,先上效果图
赶快学习起来吧
话不多说,放代码
1.
<!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>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
cursor: none;
}
a {
text-decoration: none;
}
ul,
li {
list-style: none;
}
body {
font-size: 14px;
font-family: "微软雅黑";
background: url("images/bg.jpg") top/cover;
}
#ball {
width: 15px;
height: 15px;
background: #b4ff0d;
border-radius: 50%;
position: absolute;
top: 0;
left: 0;
box-shadow: 0 0 9px 9px #f3ff67;
}
#ward {
width: 120px;
height: 30px;
z-index: 999;
background-color: #336688;
border-radius: 10px;
box-shadow: 0 0 4px #333333;
position: absolute;
left: 0;
}
#score {
width: 100px;
height: 100px;
font-size: 40px;
position: absolute;
right: 40px;
top: 40px;
color: #ff2541;
}
#wrap {
width: 90%;
height: 500px;
position: relative;
top: 100px;
left: 0;
right: 0;
margin: auto;
}
#wrap div {
width: 45px;
height: 15px;
border: 1px solid #ff645b;
position: absolute;
background: rgb(255, 99, 89);
box-shadow: 0 0 9px 1px rgb(255, 187, 136) inset;
top: 0;
left: 0;
transform-origin: top center
}
#gameover {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 300px;
height: 200px;
box-shadow: 0 0 4px #222222;
background-color: #e1e1e1;
display: none
}
#gameover p {
width: 100%;
height: 40px;
text-align: center;
font-size: 36px;
color: #336688;
margin-top: 50px;
}
#gameover span {
width: 60%;
height: 40px;
display: block;
margin: 38px auto 0;
text-align: center;
font-size: 20px;
background: #336688;
color: #ffffff;
border-radius: 10px;
line-height: 40px;
}
</style>
</head>
<body>
<div id="wrap"></div>
<div id="ball"></div>
<div id="ward"></div>
<div id="score">0分</div>
<div id="gameover">
<p>总分:74</p>
<span>确定</span>
</div>
<script type="text/javascript">
/* javascript中严格区分大小写 a!==A;
1.需要哪些元素
小球 挡板 砖块区域 初始x位置 初始y位置
2.要有那些行为
初始化init
init用来存放初始化方法
如果实例化对象调用所有方法很麻烦,所以一次性解决
创建砖块creatBrick
for循环生成砖块
计算每一个砖块初始化top和left
计算金字塔中线位置
初始化小球
初始化小球x方向移动向量
初始化小球y方向移动向量
初始化小球宽度和高度
初始化小球开始运动事件
初始化小球位置 x,y
初始化挡板
初始化挡板位置 x,y
初始化鼠标监听事件
挡板的移动
挡板中央跟随鼠标x方向移动
挡板运动边界 左 右
小球的移动
小球移动方法 requestAnimationFrame
小球x y 向量自增
碰撞检测{
1:小球和浏览器边框的碰撞
反弹 x||y
2:小球和挡板的碰撞
反弹 y
3.小球和砖块的碰撞
反弹 y && 移除砖块
}
*/
var oBall = document.querySelector("#ball"); //球
var oWard = document.querySelector("#ward"); //挡板
var oScore = document.querySelector('#score');//计分板
var oWrap = document.querySelector('#wrap'); //砖块区域
var over = document.querySelector('#gameover'); //结束
function Breakout(ball, ward, score, wrap, over) { //打砖块小游戏对象 构造函数
this.ball = ball;
this.ward = ward;
this.scores = score;
this.wrap = wrap;
this.over = over;
this.x = 0;
this.y = 0;
this.score = 0;
}
Breakout.prototype = { //原型方法
init: function () { //初始化系统
this.ballstar(); //初始化小球
this.creatBrick(); //创建砖块
this.wardMove(); //挡板移动
},
creatBrick: function () { //砖块初始化
var x = document.documentElement.offsetWidth / 2 - document.documentElement.offsetWidth * .05, //设置居中位置
w = 45 * 2, //设置横向间距基准值
h = 15 * 2; //设置纵向间距基准值
for (var i = 1; i <= 8; i++) { //循环生成div 8层
for (var j = 0; j < i * 2 - 1; j++) { //每一层的砖块个数为 层数*2-1
var brick = document.createElement("div");
brick.style.top = (i - 1) * h + 'px';
brick.style.left = x - (i * w) + (j * w) + 'px';
this.wrap.appendChild(brick);
}
}
},
wardMove: function () { //挡板初始化
this.ward.style.top = window.innerHeight - 180 + 'px'; //初始化挡板的top位置
this.ward.style.left = this.x - 60 + 'px'; //初始化挡板的left位置居中
this.addEvent(document, 'mousemove', this.mouseMove.bind(this)); //监听鼠标移动
},
ballstar: function () { //小球初始化
var This = this;
this.y = window.innerHeight - 200; //初始化坐标X的位置 窗口底部上移200px
this.x = window.innerWidth / 2; //初始化坐标Y的位置 窗口中间部位
this.ball.style.top = this.y + 'px'; //初始化小球的top值为y
this.ball.style.left = this.x + 'px'; //初始化小球的left值为x
this.ball.speed = 10; //初始化小球的速度
this.ball.width = 15; //初始化小球的宽度
this.ball.height = 15; //初始化小球的高度
document.onclick = function () { //点击开始游戏,小球运动
This.ballMove(); //小球移动
}
},
//挡板移动
mouseMove: function (e) { //鼠标移动,挡板跟随鼠标运动
e = e || window.event; //事件对象兼容性处理
var _left = e.pageX - this.ward.offsetWidth / 2; //保证鼠标移动,挡板中间位置同步鼠标位置
_left = Math.min(window.innerWidth - this.ward.offsetWidth, _left); //挡板向右移动不能超过屏幕右边界
_left = Math.max(0, _left); //挡板向左移动不能超过屏幕左边界
this.ward.style.left = _left + 'px'; //通过设置挡板left值实现挡板移动
},
ballMove: function () { //小球开始运动
document.onclick = null; //先清除document的点击事件防止一直重置运动
this.ball.xspeed = this.ball.speed; //初始化小球x运动速度和方向 +为往左 -为往右
this.ball.yspeed = -this.ball.speed;//初始化小球y运动速度和方向 +为往上 -为往下
function auto() { //运动函数 auto 通过requestAnimationFrame递归调用实现循环
this.x += this.ball.xspeed; //x代表当前横向位置 += 横向移动速度 10 每一次都在自己原先的位置基础上+10
this.y += this.ball.yspeed; //y代表当前横向位置 += 横向移动速度 10 每一次都在自己原先的位置基础上+10
this.crash(); //碰撞检测
this.ball.style.left = this.x + 'px'; //小球运动赋值 x轴运动
this.ball.style.top = this.y + 'px'; //小球运动赋值 y轴运动
requestAnimationFrame(auto.bind(this)); //原生js动画 根据cpu运算速度来实现更新
}
auto.call(this);
},
crash: function () {
var maxWidth = window.innerWidth - this.ball.offsetWidth; //浏览器左边界=浏览器宽度-球的宽度
var maxHeight = window.innerHeight - this.ball.offsetHeight; //浏览器右边界=浏览器高度-球的高度
if (this.y >= maxHeight) { //小球掉下去之后,游戏结束
this.gameOver();
}
if (this.x >= maxWidth) {
this.ball.xspeed *= -1; //小球碰到右边墙壁后 横向移动速度取反 往返方向移动
this.x = maxWidth; //重置小球位置
}
if (this.x < 0) { //碰到左边墙 重置横向移动速度 并且重置横向位置 为0
this.ball.xspeed = this.ball.speed;
this.x = 0;
}
if (this.y < 0) { //碰到上边墙壁之后 重置纵向移动速度 以及纵向位置 为0
this.ball.yspeed = this.ball.speed;
this.y = 0;
}
//挡板碰撞检测
if (Math.abs(this.x - (this.ward.offsetLeft + (this.ward.clientWidth / 2))) < 60 && Math.abs(this.y - this.ward.offsetTop - 30) < 45) {
var color = this.ranColor();
this.ward.style.background = color;
this.ball.yspeed *= -1;
this.y = this.ward.offsetTop - 40;
}
for (var i = this.wrap.children.length - 1; i >= 0; i--) {
var ballMx = this.ball.offsetLeft + (this.ball.width / 2);
var ballMy = this.ball.offsetTop + (this.ball.height / 2);
var brickMx = (this.wrap.children[i].offsetLeft + this.wrap.offsetLeft) + (45 / 2);
var brickMy = (this.wrap.children[i].offsetTop + this.wrap.offsetTop) + (15 / 2);
if (Math.abs(ballMx - brickMx) <= 45 && Math.abs(ballMy - brickMy) <= 15) {
this.ball.yspeed *= -1;
this.y = brickMy;
this.wrap.removeChild(this.wrap.children[i]);
if (this.wrap.children.length == 0) {
this.gameOver();
}
this.scoreChange();
}
}
},
scoreChange: function () {
this.score++;
this.scores.innerHTML = this.score + '分';
},
gameOver: function () {
this.over.style.display = 'block';
this.over.children[0].innerHTML = '总分:' + this.score;
var all = document.querySelectorAll('*');
for (var i = 0; i < all.length; i++) {
all[i].style.cursor = 'auto'
}
this.ward.style.display = 'none';
this.ball.style.display = 'none';
this.over.children[1].onclick = function () {
window.location.reload();
}
},
/* getStyle: function (ele, curr) { //获取属性值
return ele.currentStyle ? parseInt(ele.currentStyle[curr]) : parseInt(getComputedStyle(ele, null)[curr]);
},*/
addEvent: function (element, e, fn) {//事件监听
return element.attachEvent ? element.attachEvent('on' + e, fn) : element.addEventListener(e, fn, false);
},
ranColor: function () { //随机颜色
var color = '#';
for (var i = 0; i < 6; i++) {
color += '0123456789abcdef'[Math.floor(Math.random() * 16)]
}
return color;
},
}
var breakout = new Breakout(oBall, oWard, oScore, oWrap, over);
breakout.init();
</script>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>新建网页</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<script type="text/javascript">
//① 绘制地图
function Map() {
//私有成员(不会随便发生变化)
var w = window.innerWidth;
var h = window.innerHeight;
//成员方法,绘制地图
this.showmap = function () {
//创建div、设置css样式、追加给body
var tu = document.createElement('div');
tu.style.width = w + "px";
tu.style.height = h + "px";
// tu.style.backgroundImage = "url(12.jpg)";
// tu.style.backgroundSize = "100%"
document.body.appendChild(tu);
}
}
//② 绘制食物
function Food() {
var len = 20;
//把食物(权值)坐标声明为公开的,以便在外部访问
this.xFood = 0;
this.yFood = 0;
this.piece = null; //页面上唯一的食物对象
//绘制
this.showfood = function () {
//创建div、设置css样式、追加给body
if (this.piece === null) {
this.piece = document.createElement('div');
this.piece.style.width = this.piece.style.height = len + "px";
this.piece.style.backgroundColor = "#b3d5f1";
this.piece.style.position = "absolute";
document.body.appendChild(this.piece);
}
//食物设置绝对定位(position/left/top)
//食物位置“随机”摆放
//移动步进值:20px
//食物“权值”坐标: X轴(0-39) Y轴(0-19)
//食物真实坐标:权值坐标 * 步进值
this.xFood = Math.floor(Math.random() * 40); //0-39的随机数
this.yFood = Math.floor(Math.random() * 20); //0-19的随机数
this.piece.style.left = this.xFood * len + "px";
this.piece.style.top = this.yFood * len + "px";
}
}
//③ 小蛇
function Snake() {
var len = 20;
this.redirect = "right"; //默认向右边移动
//后期snakebody要变化,因此声明为公开的(每个蛇节:[x坐标,y坐标,颜色,蛇节对象])
this.snakebody = [[0, 1, '#b3d5f1', null], [1, 1, '#b3d5f1', null], [2, 1, '#b3d5f1', null], [3, 1, '#cc6beb', null]];
//a.绘制小蛇
this.showsnake = function () {
//遍历小蛇的各个蛇节,并依次创建即可
for (var i = 0; i < this.snakebody.length; i++) {
//this.snakebody[i]//代表每个蛇节
//创建蛇节div
if (this.snakebody[i][3] === null) {//判断没有创建对应的蛇节
this.snakebody[i][3] = document.createElement('div');
//设置css样式(宽度、高度、颜色)
this.snakebody[i][3].style.width = this.snakebody[i][3].style.height = len + "px";
this.snakebody[i][3].style.backgroundColor = this.snakebody[i][2];
//绝对定位及位置
this.snakebody[i][3].style.position = "absolute";
//把蛇节追加给body
document.body.appendChild(this.snakebody[i][3]);
}
this.snakebody[i][3].style.left = this.snakebody[i][0] * len + "px";
this.snakebody[i][3].style.top = this.snakebody[i][1] * len + "px";
}
}
//b.移动小蛇
this.movesnake = function () {
//非蛇头蛇节(当前蛇节的新坐标 是"下个蛇节"的旧坐标)
for (var i = 0; i < this.snakebody.length - 1; i++) {
this.snakebody[i][0] = this.snakebody[i + 1][0];
this.snakebody[i][1] = this.snakebody[i + 1][1];
}
if (this.redirect == "right") {
//蛇头x坐标递增
this.snakebody[this.snakebody.length - 1][0] += 1;
}
if (this.redirect == "left") {
//蛇头x坐标递减
this.snakebody[this.snakebody.length - 1][0] -= 1;
}
if (this.redirect == "up") {
//蛇头y坐标递减
this.snakebody[this.snakebody.length - 1][1] -= 1;
}
if (this.redirect == "down") {
//蛇头y坐标递增
this.snakebody[this.snakebody.length - 1][1] += 1;
}
//判断蛇头碰到食物
//蛇头坐标
var xSnake = this.snakebody[this.snakebody.length - 1][0];
var ySnake = this.snakebody[this.snakebody.length - 1][1];
//食物坐标food.xFood/food.yFood;
if (xSnake == food.xFood && ySnake == food.yFood) {
//吃食物增加蛇节
var newjie = [this.snakebody[0][0], this.snakebody[0][1], '#b3d5f1', null];
this.snakebody.unshift(newjie);//把newjie放到数组的第一个位置去
//原食物消失,重新生成一个食物
food.showfood();
}
//控制小蛇在地图范围内移动
if (xSnake < 0 || xSnake > 77 || ySnake < 0 || ySnake > 35) {
alert('game over');
clearInterval(mytime);
return false;
}
//吃到自己判断(蛇头坐标与其他蛇节坐标一致)
for (var k = 0; k < this.snakebody.length - 1; k++) {
if (this.snakebody[k][0] == xSnake && this.snakebody[k][1] == ySnake) {
alert('game over kill you by yourself');
clearInterval(mytime);
return false;
}
}
//根据新坐标绘制小蛇
this.showsnake();
}
}
window.onload = function () {
var map = new Map();
map.showmap();
food = new Food();//声明为全局的以便在该加载事件函数外部访问
food.showfood();
snake = new Snake();//声明为全局的snake对象
snake.showsnake();
//移动小蛇
//setInterval(全局变量,时间)
mytime = setInterval("snake.movesnake()", 200);
//设置键盘事件,控制器小蛇移动方向
document.onkeydown = function (evt) {
var num = evt.keyCode;//通过事件对象获得数值码,进而知道被触发键子
if (num == 38) {
snake.redirect = "up";
}
if (num == 40) {
snake.redirect = "down";
}
if (num == 37) {
snake.redirect = "left";
}
if (num == 39) {
snake.redirect = "right";
}
}
}
</script>
<style type="text/css">
body {
margin: 0;
background: url('https://cdn.pixabay.com/photo/2020/11/04/19/22/windmill-5713337_1280.jpg') no-repeat;
background-size: cover;
}
</style>
</head>
<body></body>
</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>
<style>
body {
margin: 0;
overflow: hidden;
font-family: '微软雅黑', sans-serif;
height: 100%;
}
h1 {
font-size: 2rem;
letter-spacing: -1px;
position: absolute;
margin: 0;
top: -4px;
right: 5px;
color: #fff;
}
p {
position: absolute;
margin: 0;
top: 35px;
right: 5px;
color: #aaa;
}
</style>
</head>
<body>
<h1>弹球</h1>
<p></p>
<canvas></canvas>
<script>
const Ball_numbers = 25; //常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。
const Ball_size_min = 10;
const Ball_size_max = 20;
const Ball_speed_max = 14;
// 设定画布和初始数据
const para = document.querySelector('p');
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
// 将画布窗尺寸置为窗口内尺寸 获取当前浏览器的大小
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
// 定义一个shape的类
class Shape {
constructor(x, y, speedX, speedY, exists) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.exists = exists;
}
}
class Ball extends Shape { //Ball这个子类继承Shape这个父类
constructor(x, y, speedX, speedY, color, size, exists) {
super(x, y, speedX, speedY, exists);
this.color = color;
this.size = size;
}
draw() {
context.beginPath();// beginPath() 来声明我们现在要开始在纸上画一个图形了。
context.fillStyle = this.color;
context.arc(this.x, this.y, this.size, 0, 2 * Math.PI);//arc() 方法来在纸上画出一段圆弧。
context.fill();//fill() 方法,也就是声明我们结束了以 beginPath() 开始的绘画,
}
update() {
if ((this.x + this.size) >= width) {
this.speedX = -(this.speedX);
}
if ((this.x - this.size) <= 0) {
this.speedX = -(this.speedX);
}
if ((this.y + this.size) >= height) {
this.speedY = -(this.speedY);
}
if ((this.y - this.size) <= 0) {
this.speedY = -(this.speedY);
}
this.x += this.speedX;
this.y += this.speedY;
}
collisionDetect() { //碰撞检测
for (let j = 0; j < balls.length; j++) {
if (this !== balls[j]) { //判断当前小球是否和被循环到的小球是相同的
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size && balls[j].exists) {
balls[j].color = this.color = randomColor();
}
}
}
}
}
class EvilCircle extends Shape { //白色小圆圈
constructor(x, y, exists) {
super(x, y, exists);
this.speedX = Ball_speed_max;
this.speedY = Ball_speed_max;
this.color = "white";
this.size = 10;
this.setControls();
}
draw() {
context.beginPath();
context.strokeStyle = this.color;
context.lineWidth = 3;
context.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
context.stroke();
}
checkBounds() {
if ((this.x + this.size) >= width) {
this.x -= this.size;
}
if ((this.x - this.size) <= 0) {
this.x += this.size;
}
if ((this.y + this.size) >= height) {
this.y -= this.size;
}
if ((this.y - this.size) <= 0) {
this.y += this.size;
}
}
setControls() {
window.onkeydown = e => {
switch (e.key) {
case 'a':
case 'A':
case 'ArrowLeft':
this.x -= this.speedX;
break;
case 'l':
case 'L':
case 'ArrowRight':
this.x += this.speedX;
break;
case 'x':
case 'X':
case 'ArrowUp':
this.y -= this.speedY;
break;
case 'm':
case 'M':
case 'ArrowDown':
this.y += this.speedY;
break;
}
};
}
collisionDetect() {
for (let j = 0; j < balls.length; j++) {
if (balls[j].exists) {
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size) {
balls[j].exists = false;
count--;
para.textContent = '还剩 ' + count + ' 个球';
}
}
}
}
}
// 球和恶魔圈
const balls = [];
const evilBall = new EvilCircle(
random(0, width),
random(0, height),
true
);
let count = 0;
// 执行动画
loop();
// 生成随机数的函数
function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
// 生成随机颜色的函数
function randomColor() {
return 'rgb(' +
random(0, 255) + ', ' +
random(0, 255) + ', ' +
random(0, 255) + ')';
}
// 定义一个循环来不停地播放
function loop() {
context.fillStyle = 'rgba(0, 0, 0, 0.25)';
context.fillRect(0, 0, width, height);
while (balls.length < Ball_numbers) {
const size = random(Ball_size_min, Ball_size_max);
const ball = new Ball(
// 为避免绘制错误,球至少离画布边缘球本身一倍宽度的距离
random(0 + size, width - size),
random(0 + size, height - size),
random(-Ball_speed_max, Ball_speed_max),
random(-Ball_speed_max, Ball_speed_max),
randomColor(),
size,
true
);
balls.push(ball);
count++;
para.textContent = '还剩 ' + count + ' 个球';
}
for (let i = 0; i < balls.length; i++) {
if (balls[i].exists) {
balls[i].draw();
balls[i].update();
balls[i].collisionDetect();
}
}
evilBall.draw();
evilBall.checkBounds();
evilBall.collisionDetect();
requestAnimationFrame(loop);
//requestAnimationFrame() 方法再运行一次函数 —— 当
//一个函数正在运行时传递相同的函数名,从而每隔一小段时
//间都会运行一次这个函数,这样我们可以得到一个平滑的动
//画效果。这主要是通过递归完成的 —— 也就是说函数每次运
//行的时候都会调用自己,从而可以一遍又一遍得运行。
}
</script>
</body>
</html>