这是一款基于Canvas的游戏库(目前还不能算是引擎),仅支持AVG模式(文字冒险类游戏),之后可能会支持RPG(角色扮演类游戏)
在GameLib_AVG中,游戏由三个基本元素组成,场景、人物、对话
——V0.1—— 绘制系统:绘制图片,绘制文字 事件系统:按键事件,鼠标事件,区域精灵 剧情系统:场景,角色,对话,选项,跳转 动画系统:坐标移动,颜色变化,文字打印 音乐系统:BGM音乐,SE音效,音量调节 存档系统:存单,读档
——V0.5—— 敬请期待
将GameLib解压包,解压完成后,进入到GameLib文件夹中,打开script.js文件,输入游戏代码
如:
case 0:
Title("夏日不语")
BGM("在沙子里的微风")
break
case 1:
AVG("人民广场", "小明", "好久不见")
BGM("别着急")
break
case 2:
AVG("人民广场", "小明", "你最近去哪了")
break
case 3:
AVG("人民广场", "大莲", "我去夏威夷度假了")
break
case 4:
AVG("人民广场", "大莲", "昨天刚回来")
break
case 5:
AVG("人民广场", "小明", "夏威夷怎么样")
Select([
['很棒的体验', 1],
['还好啦,一般吧', 6],
['别提了,不堪回首', 0]
])
break
case 6:
AVG("人民广场", "大莲", "还好啦,一般吧")
break
case 7:
AVG("人民广场", "大莲", "前面有家咖啡店,去吗")
break
case 8:
AVG("人民广场", "小明", "好啊")
break
case 9:
AVG("咖啡店", "", "二人来到咖啡店")
break
case 10:
AVG("咖啡店", "店员", "两位要来点什么")
break
注:上述其实是Switch语句中的一部分,还有一部分在js/playScript.js中,在这里面可以修改游戏菜单、游戏设置和存档读档时的背景图片
case -4:
Load("读档背景");
break;
case -3:
Save("存档背景");
break;
case -2:
Options("游戏设置");
break;
case -1:
Menu("游戏菜单");
break
main.html // 游戏入口
script.js // 游戏剧本
question.md // 开发过程中遇到的问题
readme.md // 程序文档(即本文件)
image // 图片资源文件夹
js // 代码文件夹
game.js // 游戏设置
public.js // 公共脚本
mouse.js // 鼠标监听
action.js // 按键监听
animate.js // 动画效果
private.js // 私有脚本
playScript.js // 演绎剧本
如果你想要修改游戏的内容,一般只要在private.js中修改就好了 比如:对话框的颜色
格式为
API1的名字 // 注释
API1的案例 // 注释
API2的名字 // 注释
API2的案例 // 注释
在public.js中
log // 调试输出
log('你好啊'); // 输出一段话
imgLoad // 加载图片资源
var img = imgLoad('image/temp.png') // 把图片存在img中
在game.js中
game.ctx // 画布环境(canvas的context)
game.ctx.fillRect(10, 10, 100, 150); // 绘制一个矩形
(这款可以参考canvas的官方手册)
game.width // 游戏宽度
game.width = 960; // 设置游戏宽度为960px
game.height // 游戏高度
game.height 540; // 设置游戏高度为540px
game.size // 游戏字号
game.size = 16; // 设置游戏字号为18px
game.font // 游戏字体
game.font = '黑体'; // 设置游戏字体为黑体
game.fps // 游戏帧率
game.fps = 30; // 设置游戏的帧率为30帧/秒
上为属性,下为方法
game.clear // 清屏
game.clear(); // 游戏清屏
game.draw // 绘制图片
game.draw('image/temp.png', 50, 100); // 在坐标(50, 100)处绘制
game.text // 绘制文本
game.text('你好啊', 50, 100); // 在坐标(50, 100)处绘制
game.keydown // 注册按键事件
game.keydown('w', function(){ // 当w被按下时不断触发
log('w键被按下')
});
在mouse.js中
mouse.move // 鼠标移动事件
mouse.move({ // 范围为(x1,y1)到(x2,y2)的矩形区域
x1: 100,
x2: 200,
y1: 100,
y2: 200
}, function(){
log("鼠标在范围内移动");
}, function(){
log("鼠标在范围外移动");
});
mouse.click // 鼠标点击事件
mouse.click({ // 范围为(x1,y1)到(x2,y2)的矩形区域
x1: 100,
x2: 200,
y1: 100,
y2: 200
}, function(){
log("鼠标在范围内点击");
});
mouse.drag // 鼠标拖动事件
mouse.drag({ // 按下的范围
x1: 100,
y1: 100,
x2: 200,
y2: 200
}, function(xy){ // 拖动时的回调函数(鼠标坐标)
log(xy.x); // 输出鼠标所在的x坐标
});
mouse.spirit //
isMove = spirit({
x1: 100,
y1: 100,
x2: 200,
y2: 200
}, isMove, function(){
game.now = 0;
});
在animate.js中
animate.xy // 坐标变化
animate({
id: 'move', // 唯一表示符
style: 'x', // 在x坐标上变化
ori: 0, // 起点
end: 500, // 终点(x>=500就停止)
speed: 10, // 速度为10(每帧x=x+10)
accel: 1, // 加速度为1
back: true, // 达到最值后,执行相反动画
loop: true // 循环动画
})
animate.wh // 尺寸变化
animate.rgba // 颜色变化
animate({
id: 'color', // 唯一表示符
rgbaOri:[0,0,0,0], // 起始颜色
rgbaEnd:[255,255,255,1], // 最终颜色
speed: 10, // 速度为10
accel: 1, // 加速度为1
back: true, // 达到最值后,执行相反动画
loop: true // 循环动画
})
animate.text // 文字动画
animate.text(str,{
x: 100, // 绘制的位置
y: 100,
max: 10, // 每行10个字
});
基本API
game.draw(url, x, y) // 绘制图片
game.text(str, x, y) // 绘制文本
game.keyDown(key, callBack) // 按键事件
mouse.move(json, callYes, callNo) // 移动事件
mouse.click(json, callBack) // 点击事件
x = animate.xy(json) // 坐标动画
rgba = animate.rgba(json) // 颜色动画
animate.text(str,json) // 文字动画
spirit(json, isMove, clickFun) // 添加精灵
AVG的API(全在private.js中)
Menu(name) // 游戏菜单
Title(name) // 标题画面
BGM(name) // 背景音乐
AVG(place, role, say) // 场景 人物 对话
Select(array) // 分支事件
以下皆为全局定义,故请注意命名冲突
log // 自定义输出
imgLoad // 加载图片
game // 游戏对象
mouse // 鼠标对象
animate // 动画对象
p // 私有脚本的公共对象
spirit // 区域精灵
Title // 显示标题画面
Place // 绘制场景
Role // 绘制角色
Say // 绘制对话
AVG // 绘制场景、角色和对话(一般用这个)
BGM // 播放BGM
ScriptOut // 剧本外壳
ScriptIn // 剧本内核
myScript // 剧本整体
Script // 执行剧本
之后会重构成一个新的项目GameStudio,这是目前的考虑
/*
FP vs OOP
在gameLib中,我使用的是不成熟的FP(未作模块化管理)
并且将其拆分成了多了js文件(其实没必要,这样反而不利于下载)
于是,在gameStudio中,准备只有一个js文件
但在是要继续使用函数式编程还是面向对象编程上,产生了踌躇
JavaScript支持二者,那二者在JS中有何区别
写法上:
// OOP
class Person {
// 构造函数
constructor(name) {
this.name = name
}
// 属性
age = 18
// 方法
init() {
age = 8
console.log ('${this.name} Finish')
}
say() {
console.log (`${this.name}: I'm ${this.age} years old.`)
}
}
let tom = new Person ('Tom')
tom.init() // Tom Finish
tom.say () // Tom: I'm 8 years old.
// FP
let create_persion = (name) => {
// 属性
let o = {
name,
age: 18
}
// 方法
o.say = () => {
console.log (`${o.name}: I'm ${o.age} years old.`)
}
// 直接允许的函数
o.age = 8
console.log (`${o.name} Finish')
return o
}
let tom = create_persion ('Tom') // Tom Finish
tom.say () // Tom: I'm 8 years old.
二者区别:
OOP: 内部不能直接调用函数,非要的话,可以写在constructor中,但这样的话,被继承时也会调用
FP: 不能(简单)继承(需要修改原型链),且实例化两个相同对象,占用两块内存
注:其实上述的那个例子,不能算是真正的FP,它仅仅是套着函数的外壳(即最外层只有函数)
但并没有完成FP的思想,面向功能
*/