http://cdn.zsenhe.com/13ebbd5a7d714f10a999a2dba26298ee
都看过这种广告吧,武器围着小人转圈圈,被武器碰到的小怪就扣血。看着很有意思,手痒尝试着用现有的知识实现一个
就不花时间去学习游戏引擎了,用纯原生js+canvas库做一个网页版的小实现吧
首先在canvas上将玩家操控的主角画出来,贴图就不做了,直接上圆点吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<html>
<head>
<title>dddemo</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="gameMap" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("gameMap");
var context = canvas.getContext("2d");

// 通过画布宽高取得中心点坐标
var cX = canvas.width/2;
var cY = canvas.height/2;
// 圆点(人物)的半径
var r = 10;

// 让每一帧都调用draw函数更新画面
function draw() {
// 清除画布上所有像素
context.clearRect(0,0,400,400);
// 画圆
context.beginPath();
context.arc(cX,cY,r,0,2*Math.PI);
context.closePath();
context.fillStyle = "black";
context.fillText("我是人物",cX-10,cY-12,800);
context.fill();
// 重复绘制
requestAnimationFrame(draw);
}

draw();
</script>
</body>

接下来最重要的就是他边上的武器了,剑呢?就不画了,直接拿根线条代替吧

CanvasRenderingContext2D.lineTo() 是 Canvas 2D API 使用直线连接子路径的终点到 x,y 坐标的方法

子路径即是圆点所在的坐标,那么x,y目标坐标呢?我们可以使用三角函数来进行计算
设(cx,cy)为圆心所在的坐标,ang为弧度制的角(初始为0),每次draw执行的时候都更新角+speed(速度)
根据三角函数与弧度制,cos(ang) = x/圆半径,而这里的圆半径就是线的长度,因此线的坐标为
x = cos(ang)*r,加上cX的偏移量,y轴同理;于是可以推导出线的坐标为
(cX+cos(ang)*线长度,cY+sin(ang)*线长度)
ok,写出相应的代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<html>
<head>
<title>dddemo</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="gameMap" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("gameMap");
var context = canvas.getContext("2d");

// 通过画布宽高取得中心点坐标
var cX = canvas.width/2;
var cY = canvas.height/2;
// 圆点(人物)的半径
var r = 10;
// 当前角
var ang = 0;

// 让每一帧都调用draw函数更新画面
function draw() {
// 清除画布上所有像素
context.clearRect(0,0,400,400);
// 画圆
context.beginPath();
context.arc(cX,cY,r,0,2*Math.PI);
context.closePath();
context.fillStyle = "black";
context.fillText("我是人物",cX-10,cY-12,800);
context.fill();

console.log(ang);
console.log(cX+"/"+cY+"/圆坐标");
// 线的坐标
var lx = cX + Math.cos(ang)*80;
var ly = cY + Math.sin(ang)*80;
console.log(Math.cos(ang)+"/"+Math.sin(ang));
console.log("-----");

context.beginPath();
// 设置子路径(起始坐标)
context.moveTo(cX,cY);
context.lineTo(lx,ly);
context.closePath();
context.stroke();

// 更新角度
ang += 0.03;

// 重复绘制
requestAnimationFrame(draw);
}

draw();
</script>
</body>


ok,现在它会动了,接下来要让他移动。由于“武器”和“人物”的绘制都是根据圆心坐标来的,我们只需要监听wasd更改圆心的坐标就完事了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
window.addEventListener("keydown", handlerMove);

function handlerMove(event) {
var key = event.key;

switch(key) {
case "w":
cY -= 5;
break;
case "a":
cX -= 5;
break;
case "s":
cY += 5;
break;
case "d":
cX += 5;
break;
default:
break;
}
}

效果如下:

接下来我们设置几个敌人,敌人就用绿色的球球表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<html>
<head>
<title>dddemo</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="gameMap" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("gameMap");
var context = canvas.getContext("2d");

// 通过画布宽高取得中心点坐标
var cX = canvas.width/2;
var cY = canvas.height/2;
// 圆点(人物)的半径
var r = 10;
// 当前角
var ang = 0;

var mX = cX+128;
var mY = cY+128;
var mR = 10;

window.addEventListener("keydown", handlerMove);

function handlerMove(event) {
var key = event.key;

switch(key) {
case "w":
cY -= 5;
break;
case "a":
cX -= 5;
break;
case "s":
cY += 5;
break;
case "d":
cX += 5;
break;
default:
break;
}
}

// 让每一帧都调用draw函数更新画面
function draw() {
// 清除画布上所有像素
context.clearRect(0,0,400,400);
// 画圆
context.beginPath();
context.arc(cX,cY,r,0,2*Math.PI);
context.closePath();
context.fillStyle = "black";
context.fillText("我是人物",cX-10,cY-12,800);
context.fill();


// 线的坐标
var lx = cX+Math.cos(ang)*80;
var ly = cY+Math.sin(ang)*80;
console.log("圆坐标:("+cX+","+cY+")");
console.log("角:"+ang+"cos:"+Math.cos(ang));
console.log("角:"+ang+"sin:"+Math.sin(ang));


context.beginPath();
// 设置子路径(起始坐标)
context.moveTo(cX,cY);
context.lineTo(lx,ly);
context.closePath();
context.stroke();

// 更新角度
ang += 0.03;

context.beginPath();
context.arc(mX,mY,mR,0,2*Math.PI);
context.closePath();
context.fillStyle = "green";
context.fillText("我是敌人",mX-10,mY-12,800);
context.fill();


// 重复绘制
requestAnimationFrame(draw);
}



draw();
</script>
</body>

接下来在draw函数中,计算线与敌人的距离,两点间的距离公式

var dis = Math.sqrt(Math.pow((lx - mX), 2) + Math.pow((ly - mY), 2));

当被线击中时,敌人颜色变为红色,300毫秒后恢复绿色

image.png
稍微整理一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<html>
<head>
<title>dddemo</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="gameMap" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("gameMap");
var context = canvas.getContext("2d");

// 通过画布宽高取得中心点坐标
var cX = canvas.width/2;
var cY = canvas.height/2;
// 圆点(人物)的半径
var r = 10;
// 当前角
var ang = 0;

var mX = cX+128;
var mY = cY+128;
var mR = 10;
var mC = "green";
var mH = 100;

window.addEventListener("keydown", handlerMove);

function handlerMove(event) {
var key = event.key;

switch(key) {
case "w":
cY -= 5;
break;
case "a":
cX -= 5;
break;
case "s":
cY += 5;
break;
case "d":
cX += 5;
break;
default:
break;
}
}

// 让每一帧都调用draw函数更新画面
function draw() {
// 清除画布上所有像素
context.clearRect(0,0,400,400);
// 画圆
context.beginPath();
context.arc(cX,cY,r,0,2*Math.PI);
context.closePath();
context.fillStyle = "black";
context.fillText("我是人物",cX-10,cY-12,800);
context.fill();


// 线的坐标
var lx = cX+Math.cos(ang)*80;
var ly = cY+Math.sin(ang)*80;
console.log("圆坐标:("+cX+","+cY+")");
console.log("角:"+ang+"cos:"+Math.cos(ang));
console.log("角:"+ang+"sin:"+Math.sin(ang));


context.beginPath();
// 设置子路径(起始坐标)
context.moveTo(cX,cY);
context.lineTo(lx,ly);
context.closePath();
context.stroke();

// 更新角度
ang += 0.03;

if(mH>0){
context.beginPath();
context.arc(mX,mY,mR,0,2*Math.PI);
context.closePath();
context.fillStyle = mC;
context.fillText("敌人 血量:"+mH+"/100",mX-10,mY-12,800);
context.fill();
}

var dis = Math.sqrt(Math.pow((lx - mX), 2) + Math.pow((ly - mY), 2));
if(dis<mR){
mC = "red";
mH = mH-1;
if(mH<=0){
mH = 0;
mR = 0;
}
setTimeout(function(){
mC = "green";
},300);
}


// 重复绘制
requestAnimationFrame(draw);
}



draw();
</script>
</body>

完整的效果如下:

溜了,等我画好贴图整个小游戏出来