CONTENTS
- 项目原理
- 一、基础文件
- 二、ac_game_object框架
- 三、游戏地图与玩家模型的创建
项目原理
游戏中一个物体运动的原理是浏览器每秒钟刷新60次,每次我们单独计算这个物体新的位置,然后把他刷新出来,这样最终人眼看起来就是移动的效果。
对于二维的移动,我们一般抽象出某个点比如左上角的坐标 ( x , y ) (x,y) (x,y),并记下物体的宽高 w , h w,h w,h和沿 x , y x,y x,y方向的速度 v x , v y v_x,v_y vx,vy,加入物体在水平方向上匀速运动,那么位移就为: x = x 0 + v x t x=x_0+v_xt x=x0+vxt。
一、基础文件
首先我们创建主界面index.html
以及基础CSS、JS文件base.css
、base.js
。然后设置好主界面的大小和背景(此时JS文件没有功能,只用于测试):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>King of Fighters</title>
<link rel="stylesheet" href="/static/css/base.css">
<script src="/static/js/jquery-3.6.1.min.js"></script>
</head>
<body>
<div id="kof"></div>
<script type="module">
import { KOF } from '/static/js/base.js';
let kof = new KOF('kof');
</script>
</body>
</html>
#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
}
二、ac_game_object框架
项目中的背景、两个玩家一共三个元素,对于这三个元素我们都需要实现每秒钟刷新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 = $('<canvas width="1280" height="720" tabindex=0></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
}
此时的效果如下图所示: