《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端在小遊戲上的自然優點。而做爲遊戲開發者,誰不是從小遊戲開始的呢?奧利給!加油吧!