看了萧井陌在b站直播的录播第一集,收获颇大,遂记录一下;
直播中使用的语言是JavaScript,我之前学web后台的时候,对js有一个简单的了解,因为学过C++和Java,所以看录播的时候虽然有些语法不太习惯,但也能够理解;
收获主要集中在两个方面:一是写代码的方式,主要是一个思维过程;二是重构;
我最近两年才学的C++和Java,并没有写过实际的项目,感触也不多;大学的时候,自学Delphi,写过一些小程序;虽然Delphi的知识已经忘完了,但是写代码时的感觉还记得,当时写代码,就好像是记流水账,写的时候非常的畅快,和该录播的前25分钟差不多,因为当时的写的小程序代码量不大,只有数百行,心里也没有什么高内聚,低耦合,可复用之类的概念,除了debug的时候痛苦了一点,也感受不到啥缺点;学习Java的时候,慢慢的接触了面向对象的思想(虽然学习Delphi的时候,也有这个思想,但是那个时候,最大的感觉是面向控件,估计是当时学艺不精),知道了写代码不仅仅是当时能够运行就行了,还要考虑可复用,可移植,可扩展等等,但是毕竟没有经过大量代码的洗礼,还不能够深刻理解这些;
说实话,我现在也不清楚写代码的顺序,是像视频中萧老师那样,先记流水账,在重构呢,还是先抽象,再具体,比如面向接口编程;很多人推崇面向接口编程,我也尝试过,然后发现作为一个初学者,我没有把对象抽象出来的能力,前几天用Java写了一个爬虫,我开始的时候想先把框架搭出来,把对象都抽象出来,发现做不到,后来还是边写边重构;等下次再写爬虫的时候,应该就能先搭架子了;或许别人说的面向接口编程,也是说给有一定编程经验的人听的,我考虑的有些提前了,等多重构几次,或许就习惯了;
以前我写流水账就是流水账,后来学Java就是直接的面向对象,萧老师的直播帮我把这两者联系起来了,这便是我看了第一集最大的收获;
写的比较啰嗦,因为是初学者,也想顺便总结一下自己的学习历程;
直播中,萧老师有说会把代码上传的,但是我没找到,我把我看视频时跟着写的代码贴在下边,供后来者参考:
//25min时的,之后的就开始封装重构了,和这时的代码完全变样了;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>game 1</title>
<style media="screen">
canvas {
border:1px black solid;
}
</style>
</head>
<body>
<canvas id="id-canvas" width="800" height="600"></canvas>
<script>
var log = console.log.bind(console)
var canvas = document.querySelector('#id-canvas')
var context = canvas.getContext('2d')
var x = 100
var y = 100
var speed = 5
var img = new Image()
img.src = 'paddle.png'
log(img)
img.onload = function(){
context.drawImage(img, x, y)
}
var leftDown = false
var rightDown = false
// events
window.addEventListener('keyup',function(event){
log('keyup')
var k = event.key
log(k)
if(k == 'a') {
leftDown = false
} else if (k == 'd') {
rightDown = false
}
})
window.addEventListener('keydown',function(event){
var k = event.key
log(k)
if(k == 'a') {
leftDown = true
} else if (k == 'd') {
rightDown = true
}
})
//设置每秒刷新次数,即fps
setInterval(function(){
//update x
if (leftDown) {
x -= speed
} else if (rightDown) {
x += speed
}
//可以在这个地方加个限制,把图片移动的范围限制在画面中;
//dray
context.clearRect(0, 0, canvas.width, canvas.height)
context.drawImage(img, x, y)
},1000/30)
</script>
</body>
</html>
//以下是第一集的最终代码
<!DOCTYPE html>
<!--
这个注释中的东西是我看视频时的总结、记录
重构:
1.定义一个入口;
2.把所有的代码都放在入口中;
目的:高内聚,低耦合
命名规范之函数命名:
如果这个函数表达的是一个动作,那么以动词开头,不要用介词,比如to
-->
<html>
<head>
<meta charset="utf-8">
<title>game 1</title>
<style media="screen">
canvas {
border:1px black solid;
}
</style>
</head>
<body>
<canvas id="id-canvas" width="800" height="600"></canvas>
<script>
var log = console.log.bind(console)
var imageFromPath = function(path) {
var img = new Image()
img.src = path
return img
}
var Paddle = function() {
var image = imageFromPath('paddle.png')
//这个形式有点像C++中的struct
var o = {
image: image,
x: 100,
y: 500,
speed:15,
//此处最后一定要加个逗号(,),为了一致性;以后增删都简单;据说ie6会报错
}
o.moveLeft = function() {
o.x -= o.speed
}
o.moveRight = function() {
o.x += o.speed
}
//函数参数之前不加参数类型,真的好不习惯
o.collide = function(ball) {
if(ball.y + ball.image.height > o.y) {
if(ball.x > o.x && ball.x < o.x + o.image.width) {
log('相撞')
return true
}
}
return false
}
return o
}
var Ball = function() {
var image = imageFromPath('ball.png')
var o = {
image: image,
x: 100,
y: 200,
speedX:10,
speedY:10,
fired: false,
//此处最后一定要加个逗号(,),为了一致性;以后增删都简单;据说ie6会报错
}
o.move = function() {
if (o.fired) {
log('move')
if (o.x < 0 || o.x > 800) {
o.speedX = -o.speedX
}
if (o.y < 0 || o.y > 600) {
o.speedY = -o.speedY
}
//move
o.x += o.speedX
o.y += o.speedY
}
}
o.fire = function() {
o.fired = true
}
return o
}
var GuaGame = function() {
var g = {
actions: {},
keydowns: {},
}
var canvas = document.querySelector('#id-canvas')
var context = canvas.getContext('2d')
g.canvas = canvas
g.context = context
//draw
g.drawImage = function(guaImage) {
g.context.drawImage(guaImage.image, guaImage.x, guaImage.y)
}
//events
window.addEventListener('keydown',function(event){
log('keydown')
g.keydowns[event.key] = true
})
window.addEventListener('keyup',function(event){
g.keydowns[event.key] = false
})
//
g.registerAction = function(key, callback) {
g.actions[key] = callback
}
//timer:设置每秒刷新次数,即fps
setInterval(function(){
//events
var actions = Object.keys(g.actions)
for (var i = 0;i < actions.length; i++) {
var key = actions[i]
if(g.keydowns[key]) {
//如果按键被按下,调用注册的action
g.actions[key]()
}
}
//update
g.update()
//clear
context.clearRect(0, 0, canvas.width, canvas.height)
//draw
g.draw()
},1000/30)
return g
}
var __main = function() {
var game = GuaGame()
var paddle = Paddle()
var ball = Ball()
game.registerAction('a',function(){
paddle.moveLeft()
})
game.registerAction('d',function(){
paddle.moveRight()
})
game.registerAction('f',function(){
ball.fire()
})
game.update = function() {
ball.move()
//判断相撞
if(paddle.collide(ball)) {
//这里应该调用一个ball.反弹()来实现;
ball.speedY *= -1
}
}
game.draw = function() {
//draw
game.drawImage(paddle)
game.drawImage(ball)
}
}
__main()
</script>
</body>
</html>