Canvas学习实践:一款简单的动画游戏
最近学习了下Canvas绘图。。。突发奇想就有了下面这款简单的小游戏,纯属娱乐~
废话不多说,直接上代码:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>小怪兽吃豆豆</title>
<style>
#canvas { border: 1px solid #aaaaaa; display: block; margin: 20px auto; }
#score {text-align: center;position: relative;left: -565px;font-size: 24px;color: green; }
#title { display: block; margin: 10px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="title"></canvas>
<div id="score">得分: 0</div>
<canvas id="canvas">
你的浏览器居然不支持Canvas?!赶快换一个吧!!
</canvas>
</div> <script>
setTitle();
var width = 1200, height = 600, //画布大小
x = 400, y = 300, //小怪兽圆心坐标
r = 30, //小怪兽半径
r1 = 10, //豆豆半径
speed = 5, //小怪兽移动速度(px)
direction = 'right', //小怪兽当前移动方向
ddList = [], //存储画布当前所有豆豆
score = 0; //分数
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
//绘制背景画布
drawCanvas(context);
//随机生成5个豆豆
randomCircle();
drawCircle(context);
//生成小怪兽
drawRole(context);
//定时生成豆豆
var timer = setInterval(function(){
if(ddList.length > 100) {
clearInterval(timer);
alert('Game over!!!');
return;
}
clearCanvas(context);
drawCanvas(context); randomCircle();
drawCircle(context); drawRole(context);
}, 10000)
//定义键盘方向键事件
document.onkeydown = function(e) {
if(ddList.length > 100) {
clearInterval(timer);
alert('Game over!!!');
return;
}
e = e || window.event;
e.preventDefault();
switch(e.keyCode) {
case 37: //左
direction = 'left';
if(x > r) { x = x - speed; }
break;
case 38: //上
direction = 'up';
if(y > r) { y = y - speed; }
break;
case 39: //右
direction = 'right';
if(x < width - r) { x = x + speed; }
break;
case 40: //下
direction = 'down';
if(y < height - r) { y = y + speed; }
break;
}
//吃掉豆豆简单算法
for(var i = 0; i < ddList.length; i++) {
if((Math.abs(ddList[i].y - y) <= 2*r1 && Math.abs(ddList[i].x - x) <= r1)
|| (Math.abs(ddList[i].x - x) <= 2*r1 && Math.abs(ddList[i].y - y) <= r1)) {
ddList.splice(i, 1);
score++;
break;
}
}
clearCanvas(context);
drawCanvas(context);
drawCircle(context);
drawRole(context);
//刷新得分
document.getElementById('score').innerText = '得分: ' + score;
}
};
//绘制画布
function drawCanvas(context) {
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);
}
//清除画布
function clearCanvas(context) {
context.clearRect(0, 0, width, height);
}
//一次随机生成5个豆豆
function randomCircle() {
for(var i = 0; i < 5; i++) {
var x0 = Math.floor(Math.random()*(width - r1));
x0 = x0 - x0%speed;
if(x0 < r1) { x0 = r1;}
var y0 = Math.floor(Math.random()*(height - r1));
y0 = y0 - y0%speed;
if(y0 < r1) { y0 = r1;}
ddList.push({x: x0, y: y0});
}
}
//重新绘制豆豆
function drawCircle(context) {
context.beginPath();
context.fillStyle = "yellow";
for(var i = 0; i < ddList.length; i++) {
context.moveTo(ddList[i].x, ddList[i].y);
context.arc(ddList[i].x, ddList[i].y, r1, 0*Math.PI, 2*Math.PI);
}
context.fill();
}
//绘制小怪兽
function drawRole(context) {
if(direction == 'right') {
drawRightRole(context);
}else if(direction == 'left') {
drawLeftRole(context);
}else if(direction == 'up') {
drawUpRole(context);
}else {
drawDownRole(context);
}
}
//向右走小怪兽
function drawRightRole(context) {
context.lineWidth = 2;
context.strokeStyle = "red"; context.beginPath();
context.arc(x, y, r, 0.2*Math.PI, 1.8*Math.PI);
context.lineTo(x, y);
var x0 = x + parseFloat(r * Math.cos(0.2*Math.PI).toFixed(2));
var y0 = y + parseFloat(r * Math.sin(0.2*Math.PI).toFixed(2));
context.lineTo(x0, y0); context.stroke(); context.beginPath();
var offsetx = parseFloat(0.5*r * Math.cos(0.2*Math.PI).toFixed(2));
var offsety = parseFloat(0.5*r * Math.sin(0.2*Math.PI).toFixed(2));
context.moveTo(x + offsetx, y + offsety);
context.quadraticCurveTo(x, y + 0.6*r, x - offsetx, y + offsety);
context.stroke(); context.beginPath();
context.arc(x, y - 0.5*r, 5, 0*Math.PI, 2*Math.PI);
context.stroke();
}
//向左走小怪兽
function drawLeftRole(context) {
context.lineWidth = 2;
context.strokeStyle = "red"; context.beginPath();
context.arc(x, y, r, 1.2*Math.PI, 0.8*Math.PI);
context.lineTo(x, y);
var x0 = x - parseFloat(r * Math.cos(0.2*Math.PI).toFixed(2));
var y0 = y - parseFloat(r * Math.sin(0.2*Math.PI).toFixed(2));
context.lineTo(x0, y0); context.stroke(); context.beginPath();
var offsetx = parseFloat(0.5*r * Math.cos(0.2*Math.PI).toFixed(2));
var offsety = parseFloat(0.5*r * Math.sin(0.2*Math.PI).toFixed(2));
context.moveTo(x + offsetx, y + offsety);
context.quadraticCurveTo(x, y + 0.6*r, x - offsetx, y + offsety);
context.stroke(); context.beginPath();
context.arc(x, y - 0.5*r, 5, 0*Math.PI, 2*Math.PI);
context.stroke();
}
//向上走小怪兽
function drawUpRole(context) {
context.lineWidth = 2;
context.strokeStyle = "red"; context.beginPath();
context.arc(x, y, r, 1.7*Math.PI, 1.3*Math.PI);
context.lineTo(x, y);
var x0 = x + parseFloat(r * Math.sin(0.2*Math.PI).toFixed(2));
var y0 = y - parseFloat(r * Math.cos(0.2*Math.PI).toFixed(2));
context.lineTo(x0, y0); context.stroke(); context.beginPath();
var offsetx = parseFloat(0.5*r * Math.sin(0.2*Math.PI).toFixed(2));
var offsety = parseFloat(0.5*r * Math.cos(0.2*Math.PI).toFixed(2));
context.moveTo(x + offsetx, y + offsety);
context.quadraticCurveTo(x + 0.6*r, y, x + offsetx, y - offsety);
context.stroke(); context.beginPath();
context.arc(x - 0.5*r, y, 5, 0*Math.PI, 2*Math.PI);
context.stroke();
}
//向下走小怪兽
function drawDownRole(context) {
context.lineWidth = 2;
context.strokeStyle = "red"; context.beginPath();
context.arc(x, y, r, 0.7*Math.PI, 0.3*Math.PI);
context.lineTo(x, y);
var x0 = x - parseFloat(r * Math.sin(0.2*Math.PI).toFixed(2));
var y0 = y + parseFloat(r * Math.cos(0.2*Math.PI).toFixed(2));
context.lineTo(x0, y0); context.stroke(); context.beginPath();
var offsetx = parseFloat(0.5*r * Math.sin(0.2*Math.PI).toFixed(2));
var offsety = parseFloat(0.5*r * Math.cos(0.2*Math.PI).toFixed(2));
context.moveTo(x - offsetx, y + offsety);
context.quadraticCurveTo(x - 0.6*r, y, x - offsetx, y - offsety);
context.stroke(); context.beginPath();
context.arc(x + 0.5*r, y, 5, 0*Math.PI, 2*Math.PI);
context.stroke();
}
//设置标题
function setTitle() {
var canvas = document.getElementById("title");
canvas.width = 600;
canvas.height = 100;
var context = canvas.getContext("2d"); //绘制背景画布
context.fillStyle = "#fff";
context.fillRect(0,0,600,100); context.font = "italic bolder 50px serif"; //设置字体 //设置渐变色
var grd = context.createLinearGradient(150,50,450,50);
grd.addColorStop(0,"green");
grd.addColorStop(0.8,"red");
context.fillStyle = grd; context.textAlign = "center"; //文本的中心被放置在指定的位置。
context.textBaseline="middle"; //文本基线是 em 方框的正中。 context.globalAlpha = 0.5; //透明度 context.fillText("小怪兽吃豆豆",300,50); //显示填充文本
context.strokeText("小怪兽吃豆豆",300,50); //显示描边文本
} </script>
</body>
</html>
复制代码到.html文件,直接浏览器打开,用键盘方向键控制移动,游戏界面如下图所示:

学习资料:
1、https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API
2、http://caibaojian.com/canvas/
Canvas学习实践:一款简单的动画游戏的更多相关文章
- ReactNative学习实践--动画初探之加载动画
学习和实践react已经有一段时间了,在经历了从最初的彷徨到解决痛点时的兴奋,再到不断实践后遭遇问题时的苦闷,确实被这一种新的思维方式和开发模式所折服,react不是万能的,在很多场景下滥用反而会适得 ...
- canvas学习之制作动画
html部分 ...... <body> <canvas id="myCanvas" width="400" height="400 ...
- Appium学习实践(二)Python简单脚本以及元素的属性设置
1.简单的Python脚本 Appium中的设置与Appium学习实践(一)简易运行Appium中的一致 Launch后,执行脚本 #coding:utf-8 import unittest impo ...
- 带着canvas去流浪系列之九 粒子动画【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- canvas学习之API整理笔记(二)
前面我整理过一篇文章canvas学习之API整理笔记(一),从这篇文章我们已经可以基本了解到常用绘图的API.简单的变换和动画.而本篇文章的主要内容包括高级动画.像素操作.性能优化等知识点,讲解每个知 ...
- Canvas 最佳实践(性能篇)
Canvas 想必前端同学们都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形.目前,所有的主流浏览器都支持 Canvas. Canvas 最常见的用途是渲 ...
- canvas学习和面向对象(二)
Canvas 学习(二) 上一篇Canvas 学习(一)中我是用canvas绘制了一些基本和组合的图形. 现在开始绘制图片和动画帧,以及面向对象的升级版本. 还是一样,看代码,所有的代码都托管在git ...
- ReactNative学习实践--Navigator实践
离上次写RN笔记有一段时间了,期间参与了一个新项目,只在最近的空余时间继续学习实践,因此进度比较缓慢,不过这并不代表没有新进展,其实这个小东西离上次发文时已经有了相当大的变化了,其中影响最大的变化就是 ...
- 推荐一款简单易用线上引流测试工具:GoReplay
一. 引流测试产生背景 日常大部分的测试工作都是在测试环境下,通过模拟用户的行为来对系统进行验证,包括功能以及性能.在这个过程中,你可能会遇到以下问题: 用户访问行为比较复杂,模拟很难和用户行为一致, ...
随机推荐
- 【JZOJ4744】【NOIP2016提高A组模拟9.2】同余
题目描述 输入 输出 样例输入 5 2 1 5 2 3 7 1 3 2 1 2 5 3 0 样例输出 2 1 数据范围 解法 题目允许离线,且没有修改操作. 考虑把一个询问拆分成两个形如"a ...
- jQuery动态加载动画spin.js
在线演示 本地下载
- day39-Spring 14-Spring的JDBC模板:DBCP连接池配置
一般常用的连接池是DBCP和C3P0. package cn.itcast.spring3.demo1; import java.sql.DriverManager; import org.junit ...
- Leetcode819.Most Common Word最常见的单词
给定一个段落 (paragraph) 和一个禁用单词列表 (banned).返回出现次数最多,同时不在禁用列表中的单词.题目保证至少有一个词不在禁用列表中,而且答案唯一. 禁用列表中的单词用小写字母表 ...
- Effective Modern C++:06lambda表达式
lambda表达式实际上是语法糖,任何lambda表达式能做到的,手动都能做到,无非是多打几个字.但是lambda作为一种创建函数对象的手段,实在太过方便,自从有了lambda表达式,使用复杂谓词来调 ...
- ActivityManagerService
先上类图: 基本类说明和运行框架图中蓝色表示AMS进程,黄色表示app进程.1. 全局调度者在android中,AMS是activity和进程的全局调度者,也就是说系统中载入和准备载入的activit ...
- nodeJs学习-14 mysql数据库学习、Navicat管理工具
数据库: MySQL 免费.性能非常不错 缺点:集群.容灾稍微弱一点 Oracle 收费.大型应用.金融级.性能非常不错.集群.容灾非常强 缺点:贵 mySQL安装教程--nodeJsz智能社视频 ...
- toString和valueOf使得对象访问时显示一个特定格式的字符串,但是可以进行数字运算
作用 toString()的作用是返回一个反映这个对象的字符串; valueOf()的作用是返回它相应的原始值; 异同点 共同点:在 JavaScript 中,toString()方法和valueOf ...
- Vue.js 第2章 钩子函数&自定义指令&过滤器&计算属性&侦听器
目标 钩子函数 自定义指令 自定义过滤器 计算属性 监听属性 局部自定义指令 为什么需要自定义指令 为了复用,为了代码的灵活 指令的分类:全局指令,局部指令 在vm外面创建的指令 通过Vue.dire ...
- @loj - 2289@「THUWC 2017」在美妙的数学王国中畅游
目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个点编号 0 到 n-1,每个点有一个从 [0,1] 映射到 ...