《game programming patterns》 这是一本讲设计模式在游戏中的应用的书,我以为做者讲得很好,有兴趣的小伙伴能够去看看原著。若是懂得编码的快乐的话,你必定会乐在其中的。这也是原著里我很喜欢的一句话: if you want to make something fun, have fun making it. (若是你想作出让人享受的东西,那就享受作它的过程)前端
我接下来的文章也会围绕这本书展开,使用React+JavaScript实现一些这本书上的简单例子。 好了,立刻开始吧。git
在学习游戏设计模式以前,有必要先了解一下继承github
MilK:你能不能用键盘控制DIV移动。编程
丁丁:简单。设计模式
一天后...markdown
丁丁:作完了。函数
MilK:效果不错,你能不能多加几个这样的DIV。oop
丁丁:简单,复制出来就行了。性能
MilK:复制?那你也太捞了。试试用构造的方式写吧。学习
丁丁:好吧,我想一想...
单元(unit)是游戏中最简单也是最重要的一部分,想要高效的生成各类各样的元素,确定离不单元的开构造与继承。
来一个简单的构造函数:
function CreateUnit (){
this.width = 100;//宽度
this.height = 100;//高度
this.left = 100;//X坐标
this.top = 100;//Y坐标
this.v = 100;//移动速度
this.move = function (left,top) {//移动到某个坐标
this.left = left;
this.top = top;
}
}
复制代码
而后把这个单元new出来
unit = new CreateUnit();
复制代码
输出结果:
unit->CreateUnit {
width: 100,
height: 100,
left: 100,
top: 100,
v: 100,
move: ƒ (left, top),
__proto__: Object
}
复制代码
而后把属性赋予给DIV:(这里是REACT的写法,若是不用React的话能够用createElement或getElementById,我我的以为React更方便)
<div
style = {{
border:"1px black solid",
width:this.nuit.width,
height:this.nuit.height,
left:this.nuit.left-this.nuit.width/2,
top:this.nuit.top-this.nuit.height/2,
position:"absolute",
}}
/>
复制代码
这样就能看到一个长100px宽100px的框框浮动在页面上了
咱们对这个构造函数稍加修改,让它能够附上初值:
function CreateUnit (unit){
this.width = unit.width||100;//宽度
this.height = unit.height||100;//高度
this.left = unit.left||100;//X坐标
this.top = unit.top||100;//Y坐标
this.v = unit.v||100;//移动速度
this.move = function (left,top) {//移动函数
this.left = left;
this.top = top;
}
}
复制代码
不过这个最简单的确定不够,咱们不妨再定义一个Boy的构造函数,继承这个unit:
function Boy (boy){
this.name = boy.name||"boy";//名字
}
Boy.prototype = new CreateUnit({});
复制代码
就是这么简单,一个最基本的继承关系就实现了,Boy会具备本身的名字,和继承来的unit属性(有关于prototype的基础能够去百度找到更详细的教学)
如今再构造出一个Boy看看:
boy = new Boy({
name: "小明"
});
复制代码
输出结果:
boy->Boy{
name: "小明",
__proto__: CreateUnit {
width: 100,
height: 100,
left: 100,
top: 100,
v: 100,
move: ƒ (left, top),
__proto__: Object
}
}
复制代码
这里的__proto__指的是父类继承来的属性,调用父类的值不须要输入__proto__,本身没有的属性js就会自动去父类中找(知识点:原型模式,划重点,要考):
console.log(unit.width);//100,本身的属性
console.log(boy.name);//小明,本身的属性
console.log(boy.width);//100,继承来的属性
复制代码
继承实现了,是时候批开始量生产了:
boyList=[
new Boy({name:"小王"}),
new Boy({name:"小北"}),
new Boy({name:"小清"}),
new Boy({name:"小狗"})
];
复制代码
render 函数中显示:
{
this.boyList.map((item,i)=>{
return <div
key = {i}
style = {{
border:"1px black solid",
width:item.width,
height:item.height,
left:item.left-item.width/2,
top:item.top-item.height/2,
position:"absolute",
textAlign:"center",
lineHeight:item.height+"px"
}}
>
{item.name}
</div>
})
}
复制代码
效果:
能够看到4个Boy的名字重叠出如今了页面上,批量生产大功告成~
接下来就须要控制咱们的角色移动了:
this.boy.move(200,100);//把小明移动到200,100的位置
复制代码
看看效果:
还能够吧~接下来结合键盘的操做:
boyList = [new Boy({name:"小王"}),new Boy({name:"小北"}),new Boy({name:"小清"}),new Boy({name:"小狗"}),];
boy = new Boy({name:"小明"});
focus = this.boy;//焦点,键盘只控制焦点上的角色,初始值设为小明
/**
* REACT生命周期函数,组件渲染后调用
*/
componentDidMount(){
//添加键盘监听
document.addEventListener("keydown", this.onKeyDown);
}
/**
* REACT生命周期函数,组件销毁前调用
*/
componentWillUnmount(){
//键盘监听结束
document.removeEventListener("keydown", this.onKeyDown);
}
/**
* 键盘监听事件
* @param e
*/
onKeyDown = (e) => {
console.log(e.keyCode);
switch(e.keyCode) {
case 39://向右移动
this.focus.move(this.focus.left+this.focus.v,this.focus.top);//焦点向右移动
this.setState({});//从新渲染页面
break;
case 37://向左移动
this.focus.move(this.focus.left-this.focus.v,this.focus.top);
this.setState({});
break;
case 38://向上移动
this.focus.move(this.focus.left,this.focus.top-this.focus.v);
this.setState({});
break;
case 40://向下移动
this.focus.move(this.focus.left,this.focus.top+this.focus.v);
this.setState({});
break;
default:
break
}
};
/**
* 设置焦点
*/
setFocus = (util) => {
this.focus=util;
};
/**
* REACT生命周期主函数,用于渲染页面
* @returns {*}
*/
render() {
return (
<div className = {"game1"}>
<div
onClick = {onClick}
style = {{
border:"1px black solid",
width:this.boy.width,
height:this.boy.height,
left:this.boy.left-this.boy.width/2,
top:this.boy.top-this.boy.height/2,
position:"absolute",
textAlign:"center",
lineHeight:this.boy.height+"px"
}}
>
{this.boy.name}
</div>
{
this.boyList.map((item,i) => {//循环输出boyList
return <div
key = {i}
onClick = {onClick}
style = {{
border:"1px black solid",
width:item.width,
height:item.height,
left:item.left-item.width/2,
top:item.top-item.height/2,
position:"absolute",
textAlign:"center",
lineHeight:item.height+"px"
}}
>
{item.name}
</div>
})
}
</div>
);
}
复制代码
这里解释一下焦点focus,咱们确定得让键盘分开控制不一样的角色,因此,设置一个焦点给键盘控制,焦点就是某个角色的引用。咱们再给每个div设置一个onClick函数,把焦点设置为本身,就能够在点击这个div以后控制这个角色了。
看看效果:(虽然丑了点,可是意会就好啦,这就是一个多角色游戏的最基本实现)
为了让代码更加好看一点,把角色作成一个组件吧,修改这个组件的样式,就能按照你的喜爱创建角色啦!
BoyUnit组件:
class BoyUnit extends Component{
render() {
const {onClick,unit} = this.props;
return <div
onClick = {onClick}
style = {{
border:"1px black solid",
width:unit.width,
height:unit.height,
left:unit.left-unit.width/2,
top:unit.top-unit.height/2,
position:"absolute",
textAlign:"center",
lineHeight:unit.height+"px"
}}
>
{unit.name}
{/**这里还能够添加图片,甚至修改角色的形状**/}
{/*<img/>*/}
</div>;
}
}
复制代码
Render函数:(看起来是否是清爽不少了)
render() {
return (
<div className = {"game1"}>
{
this.boyList.map((item,i)=>{
return <BoyUnit
key = {i}
onClick = {()=>{
this.setFocus(item);
}}
unit = {item}
/>
})
}
<BoyUnit
onClick = {()=>{
this.setFocus(this.boy);
}}
unit = {this.boy}
/>
</div>
);
}
复制代码
代码优化完以后老是能让人心情舒畅,不是么~~
好了,学习React小游戏开发第一天,复习了一下JS基础,以后会学习更复杂的应用场景,写更有趣的demo,全部的demo都能在git上找到嗷。
哈哈相信你们必定都有必定的困惑,为何要用JS写游戏呢,C、C#在性能上的优点不香嘛,缘由有两点:
JavaScript做为一个脚本语言,相比较于其余语言(C,C++)更加容易理解,flash与计算机语言又有着本质上的不一样。想入门游戏,不妨从前端/JavaScript开始,若是你以为能够了的话,想作大游戏再转行C语言也不迟,由于不少编程的思惟,都是互通的,学会了思想,什么都好办。(其实主要缘由仍是由于大学第一年就学会了用JS作动画,很方便不是么)
我这我的嘛,是从4399小游戏的时代过来的,即便如今打开也是满满的童年味。小时候想玩游戏了,打开4399,随便点开一个游戏,立刻就能玩,不须要注册什么帐号,不用繁琐的安装流程,方便的启动老是能让人想点开更多的游戏。这就是WEB端在小游戏上的自然优点。而做为游戏开发者,谁不是从小游戏开始的呢?奥利给!加油吧!