游戏中一个物体运动的原理是浏览器每秒钟刷新60次,每次我们单独计算这个物体新的位置,然后把他刷新出来,这样最终人眼看起来就是移动的效果。
对于二维的移动,我们一般抽象出某个点比如左上角的坐标(x,y)(x,y)(x,y),并记下物体的宽高w,hw,hw,h和沿x,yx,yx,y方向的速度vx,vyv_x,v_yvx,vy,加入物体在水平方向上匀速运动,那么位移就为:x=x0+vxtx=x_0+v_xtx=x0+vxt。
首先我们创建主界面index.html
以及基础CSS、JS文件base.css
、base.js
。然后设置好主界面的大小和背景(此时JS文件没有功能,只用于测试):
King of Fighters
#kof {width: 1280px;height: 720px;background-image: url('/static/images/background/1.gif');background-size: 100% 100%;background-position: top;
}
class KOF {constructor(id) {this.$kof = $('#' + id);console.log(this.$kof);}
}export {KOF
}
项目中的背景、两个玩家一共三个元素,对于这三个元素我们都需要实现每秒钟刷新60次,所以我们可以让这三个元素继承至同一个元素,我们在/static/js
中创建一个新的文件夹ac_game_object
,并在该文件夹创建base.js
(为了区分之后称为ac_game_object/base.js
)。该文件框架代码如下:
let AC_GAME_OBJECTS = [];class AcGameObject {constructor() {AC_GAME_OBJECTS.push(this);this.timedelta = 0; // 存储当前这帧距离上一帧的时间间隔this.has_call_start = false; // 表示当前对象是否执行过start()}start() { // 初始化执行一次}update() { // 除第一帧外每帧执行一次}destroy() { // 删除当前对象for (let i in AC_GAME_OBJECTS) {if (AC_GAME_OBJECTS[i] === this) {AC_GAME_OBJECTS.splice(i, 1);break;}}}
}let last_timestamp; // 记录上一帧在什么时间执行let AC_GAME_OBJECTS_FRAME = (timestamp) => {for (let obj of AC_GAME_OBJECTS) {if (!obj.has_call_start) {obj.start();obj.has_call_start = true;} else {obj.timedelta = timestamp - last_timestamp;obj.update();}}last_timestamp = timestamp;requestAnimationFrame(AC_GAME_OBJECTS_FRAME);
}requestAnimationFrame(AC_GAME_OBJECTS_FRAME);
使用canvas
设计基本的地图和玩家,/static/js/game_map/base.js
代码如下:
import { AcGameObject } from '/static/js/ac_game_object/base.js'class GameMap extends AcGameObject {constructor(root) {super();this.root = root;this.$canvas = $('');this.ctx = this.$canvas[0].getContext('2d');this.root.$kof.append(this.$canvas);this.$canvas.focus();}start() {}update() {this.render();}render() { // 渲染函数// 每一帧需要清空地图,不然看到的效果就不是物体在移动,而是拖出一条线this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);this.ctx.fillStyle = 'black';this.ctx.fillRect(0, 0, this.$canvas.width(), this.$canvas.height());}
}export {GameMap
}
/static/js/player/base.js
代码如下:
import { AcGameObject } from "/static/js/ac_game_object/base.js";class Player extends AcGameObject {constructor(root, info) {super();this.root = root;this.id = info.id;this.x = info.x;this.y = info.y;this.width = info.width;this.height = info.height;this.color = info.color;this.vx = 0;this.vy = 0;this.speedx = 400; // 水平速度this.speedy = 1000; // 跳起的初始速度this.ctx = this.root.game_map.ctx;}start() {}update() {this.render();}render() {this.ctx.fillStyle = this.color;this.ctx.fillRect(this.x, this.y, this.width, this.height);}
}export {Player
}
主文件base.js
代码如下:
import { GameMap } from '/static/js/game_map/base.js';
import { Player } from '/static/js/player/base.js';class KOF {constructor(id) {this.$kof = $('#' + id);this.game_map = new GameMap(this);this.players = [new Player(this, {id: 0,x: 200,y: this.$kof.height() - 200,width: 120,height: 200,color: 'blue'}),new Player(this, {id: 1,x: 900,y: this.$kof.height() - 200,width: 120,height: 200,color: 'red'}),]}
}export {KOF
}
此时的效果如下图所示: