相当注重模块化,主要分几部分划分设计(导演类、主程、数据类)。
一些准备工作1.Babel(在项目中安装有效) 2.新的谷歌浏览器(不在微信的工具中开发)。
<!DOCTYPE>
<html>
<head>
<meta charset="UTF-8">
<title>web birdy</title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<!--模拟小游戏尺寸大小-->
<canvas id="game_canvas" width="375" height="667"></canvas>
<!--入口js-->
<script src="game.js" type="module"></script>
</body>
</html>
game.js必须有
//浏览器原因,必须加上.js
import {Main} from "./Main.js";
new Main();
main主程:初始化整个游戏的精灵,作为游戏开始的入口里面包含静态的加载准备、数据保存、导演
/**
* Created by Administrator on 2018/4/5.
*/
import {ResourceLoader} from "./js/base/ResourceLoader.js";
import {BackGround} from "./js/runtime/BackGround.js";
import {DataStore} from "./js/base/DataStore.js";
import {Diector} from "./js/Diector.js";
export class Main{
constructor(){
this.canvas=document.getElementById('game_canvas');
this.ctx=this.canvas.getContext('2d');
this.dataStore=DataStore.getInstance();
//静态类自己new
const loader=ResourceLoader.creat();
//确保所有资源加载好执行,通过loader.onLoaded返回来
loader.onLoaded(map=>this.onResourceFirstLoaded(map));
// Diector.getInstance();
}
onResourceFirstLoaded(map){
//资源准备就绪开始保存数据和初始化
console.log(map);
//长期保存
this.dataStore.ctx=this.ctx;
this.dataStore.res=map;
this.init();
//描绘背景图
// let background=new BackGround(this.ctx,map.get('background'));
// background.draw();
}
init(){
//保存背景数据
this.dataStore
.put('background',
new BackGround(this.ctx,this.dataStore.res.get('background')));
//导演类运行
Diector.getInstance().run();
}
}
Resources、ResourceLoader静态资源各就各位的处理
export const Resources=[
['background', 'res/background.png'],
['land', 'res/land.png'],
['pencilUp', 'res/pie_up.png'],
['pencilDown', 'res/pie_down.png'],
['birds', 'res/birds.png'],
['startButton', 'res/start_button.png']
];
//资源文件加载器,确保canvas在图片资源加载完成后才进行渲染
import {Resources} from "./Resources.js";
export class ResourceLoader{
constructor(){
this.map=new Map(Resources);
//遍历map
for(let[key,value] of this.map){
console.log(key);
const image=new Image();
image.src=value;
//重新转为图片对象还回去
this.map.set(key,image);
}
}
onLoaded(callback){
let loadedCount=0;
for (let value of this.map.values()){
//图片加载完
value.οnlοad=()=>{
loadedCount++;
//箭头函数防this指向value.onload
if(loadedCount >=this.map.size){
//返回出去
callback(this.map);
}
}
}
}
static creat(){
//自动new
return new ResourceLoader();
}
}
BackGround.js单独处理背景层,后面的各单位显示同样有单独的js处理
//背景
import {Sprite} from "../base/Sprite.js";
//继承精灵类
export class BackGround extends Sprite{
constructor(ctx,image){
//父类super
super(ctx,image,
0, 0,
image.width, image.height,
0, 0,
window.innerWidth,window.innerHeight);
}
}
Sprite.js精灵类,负责描绘单位
export class Sprite{
constructor(ctx=null,
img = null,
srcX = 0,
srcY = 0,
srcW = 0,
srcH = 0,
x = 0, y = 0,
width = 0, height = 0){
this.ctx = ctx;
this.img = img;
this.srcX = srcX;
this.srcY = srcY;
this.srcW = srcW;
this.srcH = srcH;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
* img 传入Image对象
* srcX 要剪裁的起始X坐标
* srcY 要剪裁的起始Y坐标
* srcW 剪裁的宽度
* srcH 剪裁的高度
* x 放置的x坐标
* y 放置的y坐标
* width 要使用的宽度
* height 要使用的高度
*/
draw(){
this.ctx.drawImage(
this.img,
this.srcX,
this.srcY,
this.srcW,
this.srcH,
this.x,
this.y,
this.width,
this.height
);
}
}
DataStore.js专门保存数据信息区别于map
//长期保存
export class DataStore{
static getInstance(){
if(!DataStore.instance){
DataStore.instance=new DataStore();
}
return DataStore.instance;
}
constructor(){
//随时销毁放map
this.map=new Map();
}
put(key,value){
this.map.set(key,value);
//链式操作
return this;
}
get(key){
return this.map.get(key);
}
destroy(){
for(let value of this.map.values()){
value=null;
}
}
}
Director.js导演,叫开机就开机
//导演类
import {DataStore} from "./base/DataStore.js";
export class Director{
constructor(){
this.dataStore=DataStore.getInstance();
console.log("构造器初始化");
}
static getInstance(){
//单例模式,其他地方怎么调用都只执行一次
if(!Director.instance){
Director.instance=new Director();
}
console.log(Director.instance);
return Director.instance;
}
run(){
const backgroundSprite=this.dataStore.get('background');
backgroundSprite.draw();
}
}