怎样创建一块画布
1、创造一个基类
src/scripts/AcGameObject.js
const AC_GAME_OBJECTS = []; // 存储所有游戏对象
export class AcGameObject {
constructor(){//构造函数
AC_GAME_OBJECTS.push(this); // 把当前对象存入 AC_GAME_OBJECTS 数组中
this.timedelta = 0; // 当前帧与上一帧执行的时间间隔
this.has_called_start = false; // 判断当前对象有没有执行过
}
start(){ // 只执行一次
}
update(){ // 每一帧执行一次,除了第一帧之外
}
on_destory(){ // 删除之前执行
}
destory(){
this.on_destory();
for(let i in AC_GAME_OBJECTS){
const obj = AC_GAME_OBJECTS[i];
if(obj === this){
AC_GAME_OBJECTS.splice(i); // 从数组中删除一个元素
break;
}
}
}
}
let last_timestamp; // 上一次执行的时刻
const step = (timestamp) =>{
for(let obj of AC_GAME_OBJECTS){ // of遍历的是值,in遍历的是下标
if(!obj.has_called_start) {
obj.has_called_start = true;
obj.start();
} else {
obj.timedelta = timestamp - last_timestamp;
obj.update();
}
}
last_timestamp = timestamp;
requestAnimationFrame(step); // 递归
}
requestAnimationFrame(step)
/*
requestAnimationFrame() 告诉浏览器——你希望执行一个动画,
并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
顾名思义,请求动画帧,也称 帧循环。
其实就是该API能以浏览器的显示频率来作为其动画动作的频率,
比如浏览器每16.7ms刷新一次,动画回调也每16.7ms调用一次,这样就不会存在过度绘制的问题,动画不会掉帧,自然流畅。
*/
2、写基类的继承类
src/scripts/GameMap.js
import { AcGameObject } from "./AcGameObjects"; // export default 是不用加大括号的,每一个文件最多import一个default
export class GameMap extends AcGameObject {
constructor(ctx,parent){
super(); // 执行基类的构造函数
this.ctx=ctx; // 画布
this.parent = parent; // 画布的父元素,用来动态修改画布的长宽
this.L = 0; // 存储每一个格子的绝对距离
this.rows = 13;
this.cols = 13;
}
start(){
}
update_size(){
this.L = Math.min(this.parent.clientWidth / this.cols, this.parent.clientHeight / this.rows); // 求每个小正方形的边长最小值
this.ctx.canvas.width = this.L * this.cols;
this.ctx.canvas.height = this.L * this.rows;
}
update(){
this.update_size();
this.render();
}
render(){
const color_even = "#AAD751", color_odd = "#A2D149";
for(let r = 0; r < this.rows; r++){
for(let c = 0; c < this.cols ; c++){
if( (r + c) % 2 == 0 ){
this.ctx.fillStyle = color_even;
} else {
this.ctx.fillStyle = color_odd;
}
this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L);
}
}
}
}
3、描绘地图
/src/components/GameMap.vue
<template>
<div ref="parent" class = "gamemap"> <!--通过ref,将这里的div和script里的canvas产生关联-->
<canvas ref="canvas"> <!-- 画布 -->
</canvas>
</div>
</template>
<script>
import { GameMap } from "@/assets/scripts/GameMap.js"
import { ref, onMounted } from 'vue'
export default {
setup(){
let parent = ref(null);
let canvas = ref(null);
onMounted(() => {
new GameMap(canvas.value.getContext('2d'), parent.value); // .value是因为它是ref对象。获取这个元素的context,图像稍后将在此被渲染
});
return {
parent,
canvas,
}
},
}
</script>
<style scoped>
div.gamemap{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
}
</style>
4、单纯用css属性开辟一块纯色区域,并把游戏地图挂载到这块区域上
/src/components/PlayGround.vue
<template>
<div class = "playground">
<GameMap />
</div>
</template>
<script>
import GameMap from './GameMap.vue';
export default {
components:{
GameMap,
}
}
</script>
<style>
div.playground {
width : 60vw;
height: 70vh;
background: lightblue;
margin: 40px auto
}
</style>