本文章是由機器翻譯。
遊戲開發
一小時完成網路遊戲設計
你不需要完全新技能集開發的遊戲。事實上,您現有的 Web 開發技能,在 HTML、 CSS、 JavaScript 等等都為種類繁多的遊戲很好。當你建立一個遊戲與網路技術時,它將運行在幾乎任何設備使用瀏覽器上。
為了證明這一點,我將演示如何構建一個遊戲,從零開始使用 Web 技術和兩個外部的庫,和我會在一小時以內。我將介紹各種遊戲開發主題,從基本的設計和佈局、 控制項和精靈,到 arti正式人工智慧 (AI) 為一個簡單的對手。我甚至要來開發遊戲,所以它適用于個人電腦、 平板電腦和智慧手機。如果你有一些作為 Web 開發人員或另一發展領域,程式設計的經驗但是沒有編寫遊戲的體驗,這篇文章會讓你開始。如果你給我一個小時,我答應教你幾招。
獲取啟動並運行
Visual Studio,這將使 Web 應用程式的快速執行,當更改的所有開發會都做一定要有最新版本的Visual Studio(在下載 bit.ly/1xEjEnX) 所以你們可以跟隨。我使用Visual Studio2013 Pro,但與Visual Studio2013年社區更新代碼。
此應用程式將需要沒有伺服器代碼,所以我開始在Visual Studio中創建一個新的空 Web 頁專案。我將使用空的 C# 範本為 Web 網站選擇 Visual C# 選項後選擇檔 |新 |ASP.NET空的 Web 網站。
索引 HTML 檔案需要只是三個資源:jQuery,主樣式表和一個主要的 JavaScript 檔。我將一個空的 CSS 檔添加到專案稱為 style.css 和一個空的 JavaScript 檔,稱為 ping.js,以避免載入頁面時出現錯誤:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script>
<script src="ping.js"></script>
<link rel="stylesheet" href="style.css"></script>
</head>
<body>
</body>
</html>
基本設計
我正在建造的這場比賽是我叫平龐變種。坪已基本上相同的規則以及乒乓球館、 除,或者球員抓住了球,當說到他們可以然後火球回直接或角度向上或向下。通常,最好的是畫如何你會喜歡這個遊戲,看在你建造了它之前。這場比賽,我想要看的總體佈局中所示圖 1。
圖 1 坪的總體設計
一旦已經研發出遊戲的設計佈局就只需將每個元素添加到 HTML 建立的遊戲。一件事要注意,雖然,是分組的記分板和控制,以確保他們坐在一起。這麼一個接一個,你可以看到我已經添加了元素,如中所示圖 2。
圖 2 初始的 HTML 佈局
<div id="arena">
<div id="score">
<h1>
<span id="playerScore">0</span>
-
<span id="opponentScore">0</span>
</h1>
</div>
<div id="player"></div>
<div id="opponent"></div>
<div id="ball"></div>
<div id="controls-left">
<div id="up"></div>
<div id="down"></div>
</div>
<div id="controls-right">
<div id="left"></div>
<div id="right"></div>
</div>
</div>
玩的風格
如果你被載入此頁,你不會看到任何因為沒有應用樣式。我已設置 main.css 檔連結在我的 HTML 中,所以將所有 css 檔置於一個具有該名稱的新檔。我要做的第一件事是,一切都在螢幕上的位置。頁面的主體需要佔用整個螢幕,所以我會成立,第一:
body {
margin: 0px;
height: 100%;
}
第二,我需要有競技場舞臺背景圖像以填充整個螢幕 (請參閱圖 3) 應用:
#arena {
background-image: url(arena.png);
background-size: 100% 100%;
margin: 0px;
width: 100%;
height: 100%;
overflow: hidden;
}
圖 3 的舞臺背景圖像
接下來,我會位置記分板。我想這顯示頂部和中心的其他元素。命令的位置:絕對讓我把它放哪裡然後離開:50%置於它中途橫跨頂部的視窗,但起始記分牌元素的左側。為了確保它完全為中心,我使用的變換屬性和 z-索引屬性可確保它始終是在頂部:
#score {
position: absolute;
z-index: 1000;
left: 50%;
top: 5%;
transform: translate(-50%, 0%);
}
我也想要復古主題的文本字體。大多數現代瀏覽器讓我包括我自己的字體。我找到了適當的按下啟動 2 P 字體從 codeman38 (zone38.net)。若要將字體添加到記分板,我必須創建新的字體:
@font-face {
font-family: 'PressStart2P';
src: url('PressStart2P.woff');
}
現在,分數都在一個 h1 標籤,這樣就可以把所有的 h1 標籤的字體。只是以防萬一的字體是缺掉的我將提供幾個備份選項:
h1 {
font-family: 'PressStart2P', 'Georgia', serif;
}
對於其他的元素,我將使用圖像雪碧表。雪碧表包含我需要為遊戲在一個檔中的所有圖像 (見圖 4)。
圖 4 坪的雪碧表
此工作表包含有圖像的任何元素會分配的 sprite 類。然後,對於每個元素,我將使用背景位置來定義的雪碧表的哪一部分想要顯示:
.sprite {
background-image: url("sprites.png");
width: 128px;
height: 128px;
}
接下來,我會將 sprite 類添加到將使用雪碧表的所有元素。我必須簡要地跳回 HTML 來做到這一點:
<div id="player" class="sprite"></div>
<div id="opponent" class="sprite"></div>
<div id="ball" class="sprite"></div>
<div id="controls-left">
<div id="up" class="sprite"></div>
<div id="down" class="sprite"></div>
</div>
<div id="controls-right">
<div id="left" class="sprite"></div>
<div id="right" class="sprite"></div>
</div>
現在,我需要指明每個精靈中的每個元素的表上的位置。再次,我會做這個使用背景的位置,如中所示圖 5。
圖 5 為雪碧表添加偏移量
#player {
position: absolute;
background-position: 0px 128px;
}
#opponent {
position: absolute;
background-position: 0px 0px;
}
#ball {
position: absolute;
background-position: 128px 128px;
}
#right {
background-position: 64px 192px;
}
#left {
background-position: 64px 0px;
}
#down {
background-position: 128px 192px;
}
#up {
background-position: 128px 0px;
}
位置:絕對財產上的球員,對手和球會讓我移動它們使用 JavaScript。如果你看看頁面現在,你會看到這些控制項和球有沒有必要件連接到它們。這是因為雪碧大小都小於預設 128 圖元的所以我會調整到合適的尺寸。還有只有一個球,所以我會直接將其大小設置:
#ball {
position: absolute;
width: 64px;
height: 64px;
background-position: 128px 128px;
}
有四個控制元件 (按鈕,使用者可以按移動播放機),所以它理應由我來為他們做一個特殊的階層。所以他們有一個小的空間,在他們身邊,我也會添加邊距:
.control {
margin: 16px;
width: 64px;
height: 64px;
}
在添加此類之後, 這款遊戲有多好看的控制項:
<div id="controls-left">
<div id="up" class="sprite control"></div>
<div id="down" class="sprite control"></div>
</div>
<div id="controls-right">
<div id="left" class="sprite control"></div>
<div id="right" class="sprite control"></div>
</div>
我需要做的最後一件事是控制項的位置,所以當頁面在行動裝置上運行時,他們是由使用者的拇指。我會把它們貼到底部的角落:
#controls-left {
position: absolute;
left: 0; bottom: 0;
}
#controls-right {
position: absolute;
right: 0; bottom: 0;
}
一個很好的這種設計是一切設置相對位置。這意味著螢幕可以有多種不同尺寸時仍然使遊戲看起來很好。
跟隨,跳動的球
現在我會讓球移動。JavaScript 代碼,我在上面提到的檔稱為 ping.js,在 HTML 中,只是像我一樣用 CSS。我會將此代碼添加到具有該名稱的新檔。要球和球員,每個物件,但會用於物件的原廠模式。
這是一個簡單的概念。您在調用它時,球函數會創建一個新的球。那裡是沒有需要使用 new 關鍵字。這種模式降低了一些圍繞著這個混亂變數通過澄清可用的物件屬性。因為我只有一個小時來做這個遊戲,我需要儘量減少任何容易混淆的概念。
這種模式的結構作簡單的球類,示圖 6。
圖 6 球類
var Ball = function( {
// List of variables only the object can see (private variables).
var velocity = [0,0];
var position = [0,0];
var element = $('#ball');
var paused = false;
// Method that moves the ball based on its velocity. This method is only used
// internally and will not be made accessible outside of the object.
function move(t) {
}
// Update the state of the ball, which for now just checks
// if the play is paused and moves the ball if it is not.
// This function will be provided as a method on the object.
function update(t) {
// First the motion of the ball is handled
if(!paused) {
move(t);
}
}
// Pause the ball motion.
function pause() {
paused = true;
}
// Start the ball motion.
function start() {
paused = false;
}
// Now explicitly set what consumers of the Ball object can use.
// Right now this will just be the ability to update the state of the ball,
// and start and stop the motion of the ball.
return {
update: update,
pause: pause,
start: start
}
若要創建一個新的球,我簡單地稱為已經定義了此函數:
var ball = Ball();
現在我想要讓球移動和彈跳在螢幕周圍。首先,我需要一些時間間隔來創建動畫的球調用 update 函數。現代的瀏覽器提供一個函數,為此被稱為 requestAnimationFrame 的意思。這將函數作為參數,並將調用傳入的函數下次運行時其動畫週期。這讓球移動在光滑的步驟中,當瀏覽器已準備好更新。當它調用傳入的函數時,它將給它以秒為單位時間,因為載入該頁。這是關鍵,確保動畫是一致的隨著時間的推移。在遊戲中,requestAnimationFrame 使用如下所示:
var lastUpdate = 0;
var ball = Ball();
function update(time) {
var t = time - lastUpdate;
lastUpdate = time;
ball.update(t);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
請注意,requestAnimationFrame 在函數中,又叫球已完成更新。這可以確保連續的動畫。
雖然這段代碼將會運行,有可能是問題在腳本開始運行之前的頁面是完全載入。要避免此問題,我會踢掉代碼時載入頁面時,使用 jQuery:
var ball;
var lastUpdate;
$(document).ready(function() {
lastUpdate = 0;
ball = Ball();
requestAnimationFrame(update);
});
因為我知道球 (速度) 和自其上次更新時間的速度,我可以做一些簡單的物理,帶球向前:
var position = [300, 300];
var velocity = [-1, -1];
var move = function(t) {
position[0] += velocity[0] * t;
position[1] += velocity[1] * t;
element.css('left', position[0] + 'px');
element.css('top', position[1] + 'px');
}
嘗試運行該代碼,你會看到球移動角和關閉螢幕。第二,這很有趣,但一旦球熄滅在螢幕的邊緣,樂趣停止。因此下一步就是使球反彈在螢幕的邊緣,當在中實現圖 7。添加此代碼並運行該應用程式將顯示一個不斷的彈跳的球。
圖 7 簡單球彈跳物理
var move = function(t) {
// If the ball hit the top or bottom, reverse the vertical speed.
if (position[1] <= 0 || position[1] >= innerHeight) {
velocity[1] = -velocity[1];
}
// If the ball hit the left or right sides, reverse the horizontal speed.
if (position[0] <= 0 || position[0] >= innerWidth) {
velocity[0] = -velocity[0];
}
position[0] += velocity[0] * t;
position[1] += velocity[1] * t;
element.css('left', (position[0] - 32) + 'px');
element.css('top', (position[1] - 32) + 'px');
}
一個可移動的球員
現在正是時候讓球員物件。充實的 player 類的第一步將是玩家的要更改位置的移動功能。側變數將表明法院的哪一側球員將駐留,這將決定如何水準位置的球員。Y 值,傳遞到移動函數,將是多少,或下來播放將移動:
var Player = function (elementName, side) {
var position = [0,0];
var element = $('#'+elementName);
var move = function(y) {
}
return {
move: move,
getSide: function() { return side; },
getPosition: function() { return position; }
}
}
圖 8 列出了唱機機芯、 停止這項議案,如果玩家雪碧到達頂部或底部的視窗。
我現在可以創建兩個球員,並讓他們搬到他們的適當的螢幕邊:
player = Player('player', 'left');
player.move(0);
opponent = Player('opponent', 'right');
opponent.move(0);
圖 8 移動控制項為球員雪碧的
var move = function(y) {
// Adjust the player's position.
position[1] += y;
// If the player is off the edge of the screen, move it back.
if (position[1] <= 0) {
position[1] = 0;
}
// The height of the player is 128 pixels, so stop it before any
// part of the player extends off the screen.
if (position[1] >= innerHeight - 128) {
position[1] = innerHeight - 128;
}
// If the player is meant to stick to the right side, set the player position
// to the right edge of the screen.
if (side == 'right') {
position[0] = innerWidth - 128;
}
// Finally, update the player's position on the page.
element.css('left', position[0] + 'px');
element.css('top', position[1] + 'px');
}
鍵盤輸入
因此,在理論上,您可以移動播放機中,但它不動,沒有給出指令。將某些控制項添加到左邊的球員。你想要兩種方法來控制該玩家:使用鍵盤 (PCs) 和攻絲 (上平板電腦和手機) 的控制項。
為了確保觸摸輸入和滑鼠輸入在各種平臺上的一致性,我將使用偉大的統一框架 Hand.js (handjs.codeplex.com)。首先,我會將腳本添加到 HTML 頭部分中:
<script src="hand.minified-1.3.8.js"></script>
圖 9 演示如何使用 Hand.js 和 jQuery 來控制播放機,當你按鍵盤鍵 A 到 Z,或當你點擊控制項。
圖 9 添加觸摸和鍵盤控制
var distance = 24; // The amount to move the player each step.
$(document).ready(function() {
lastUpdate = 0;
player = Player('player', 'left');
player.move(0);
opponent = Player('opponent', 'right');
opponent.move(0);
ball = Ball();
// pointerdown is the universal event for all types of pointers -- a finger,
// a mouse, a stylus and so on.
$('#up') .bind("pointerdown", function() {player.move(-distance);});
$('#down') .bind("pointerdown", function() {player.move(distance);});
requestAnimationFrame(update);
});
$(document).keydown(function(event) {
var event = event || window.event;
// This code converts the keyCode (a number) from the event to an uppercase
// letter to make the switch statement easier to read.
switch(String.fromCharCode(event.keyCode).toUpperCase()) {
case 'A':
player.move(-distance);
break;
case 'Z':
player.move(distance);
break;
}
return false;
});
接住球
當球彈在附近,我想讓球員抓住它。當它被捉住時,球都有一個擁有者,和它跟隨該擁有者的議案。圖 10 將功能添加到球的 move 方法,允許擁有者,球將隨即展開。
圖 10 使球跟隨它的主人
var move = function(t) {
// If there is an owner, move the ball to match the owner's position.
if (owner !== undefined) {
var ownerPosition = owner.getPosition();
position[1] = ownerPosition[1] + 64;
if (owner.getSide() == 'left') {
position[0] = ownerPosition[0] + 64;
} else {
position[0] = ownerPosition[0];
}
// Otherwise, move the ball using physics. Note the horizontal bouncing
// has been removed -- ball should pass by a player if it
// isn't caught.
} else {
// If the ball hits the top or bottom, reverse the vertical speed.
if (position[1] - 32 <= 0 || position[1] + 32 >= innerHeight) {
velocity[1] = -velocity[1];
}
position[0] += velocity[0] * t;
position[1] += velocity[1] * t;
}
element.css('left', (position[0] - 32) + 'px');
element.css('top', (position[1] - 32) + 'px');
}
目前尚沒有辦法獲取的播放機物件,位置,所以我會將 getPosition 和 getSide 的訪問器添加到播放機物件:
return {
move: move,
getSide: function() { return side; },
getPosition: function() { return position; }
}
現在,如果球都有一個擁有者,它將跟隨該擁有人在附近。但我是如何確定的擁有者?有人把球接住。圖 11 演示如何確定當球員精靈之一觸及球。當發生這種情況時,我會對那個球員設置球的擁有者。
圖 11 球和球員的碰撞檢測
var update = function(t) {
// First the motion of the ball is handled.
if(!paused) {
move(t);
}
// The ball is under control of a player, no need to update.
if (owner !== undefined) {
return;
}
// First, check if the ball is about to be grabbed by the player.
var playerPosition = player.getPosition();
if (position[0] <= 128 &&
position[1] >= playerPosition[1] &&
position[1] <= playerPosition[1] + 128) {
console.log("Grabbed by player!");
owner = player;
}
// Then the opponent...
var opponentPosition = opponent.getPosition();
if (position[0] >= innerWidth - 128 &&
position[1] >= opponentPosition[1] &&
position[1] <= opponentPosition[1] + 128) {
console.log("Grabbed by opponent!");
owner = opponent;
}
如果您嘗試在玩遊戲,你會發現皮球跳離螢幕的頂部,您可以移動玩家可以捕捉到它。現在,你怎麼才能扔掉它?那是右側控制項 — — 瞄球。圖 12 將"火"功能添加到播放機中,只要目標屬性。
圖 12 瞄準和射擊球
var aim = 0;
var fire = function() {
// Safety check: if the ball doesn't have an owner, don't not mess with it.
if (ball.getOwner() !== this) {
return;
}
var v = [0,0];
// Depending on the side the player is on, different directions will be thrown.
// The ball should move at the same speed, regardless of direction --
// with some math you can determine that moving .707 pixels on the
// x and y directions is the same speed as moving one pixel in just one direction.
if (side == 'left') {
switch(aim) {
case -1:
v = [.707, -.707];
break;
case 0:
v = [1,0];
break;
case 1:
v = [.707, .707];
}
} else {
switch(aim) {
case -1:
v = [-.707, -.707];
break;
case 0:
v = [-1,0];
break;
case 1:
v = [-.707, .707];
}
}
ball.setVelocity(v);
// Release control of the ball.
ball.setOwner(undefined);
}
// The rest of the Ball definition code goes here...
return {
move: move,
fire: fire,
getSide: function() { return side; },
setAim: function(a) { aim = a; },
getPosition: function() { return position; },
}
圖 13 增強球員的目標和防火功能的鍵盤功能。針對會略有不同。時,釋放出的瞄準的關鍵,目的是將會返回到簡單明瞭。
圖 13 集球員的目標函數
$(document).keydown(function(event) {
var event = event || window.event;
switch(String.fromCharCode(event.keyCode).toUpperCase()) {
case 'A':
player.move(-distance);
break;
case 'Z':
player.move(distance);
break;
case 'K':
player.setAim(-1);
break;
case 'M':
player.setAim(1);
break;
case ' ':
player.fire();
break;
}
return false;
});
$(document).keyup(function(event) {
var event = event || window.event;
switch(String.fromCharCode(event.keyCode).toUpperCase()) {
case 'K':
case 'M':
player.setAim(0);
break;
}
return false;
});
最後加入將觸摸支援的所有控制項。我會讓物權變動玩家的目的上的控制項。因此在螢幕上任意位置觸摸激發了球,我也會貢獻它:
$('#left') .bind("pointerdown", function() {player.setAim(-1);});
$('#right') .bind("pointerdown", function() {player.setAim(1);});
$('#left') .bind("pointerup", function() {player.setAim(0);});
$('#right') .bind("pointerup", function() {player.setAim(0);});
$('body') .bind("pointerdown", function() {player.fire();});
保留得分
當鋼球通過一名球員時,我想要改變評分並把球給該玩家。所以我可以單獨評分從任何現有的物件,我將使用自訂事件。更新功能越來越長,所以我會添加一個新的私有函數,稱為 checkScored:
function checkScored() {
if (position[0] <= 0) {
pause();
$(document).trigger('ping:opponentScored');
}
if (position[0] >= innerWidth) {
pause();
$(document).trigger('ping:playerScored');
}
}
圖 14 顯示了回應這些事件,以更新分數並交出球的代碼。將此代碼添加到 JavaScript 文檔的底部。
圖 14 更新記分牌
$(document).on('ping:playerScored', function(e) {
console.log('player scored!');
score[0]++;
$('#playerScore').text(score[0]);
ball.setOwner(opponent);
ball.start();
});
$(document).on('ping:opponentScored', function(e) {
console.log('opponent scored!');
score[1]++;
$('#opponentScore').text(score[1]);
ball.setOwner(player);
ball.start();
});
現在當球使它過去的你的對手 (這不難,因為對手不動) 你的分數將會上漲,和球會交給對手。然而,對手就會抓住球。
耍小聰明
你幾乎有一場比賽。要是你有一個人來玩。作為最後一步,我會說明如何控制與簡單的 AI 對手。對手將試著保持平行帶球,隨著。如果對手接住球,它將隨機移動和球在一個隨機的方向射擊。若要使 AI 感覺有點更像人類,我將添加中所做的一切的延誤。這並不是高度智慧化的 AI,提醒你一下,但它將一些可以玩的比賽。
設計這種系統時,時,好想在國家。AI 對手有三種可能狀態:之後,針對槍擊事件等。我會採取以下行動來添加更多的人的元素之間的狀態。開始只是 AI 物件:
function AI(playerToControl) {
var ctl = playerToControl;
var State = {
WAITING: 0,
FOLLOWING: 1,
AIMING: 2
}
var currentState = State.FOLLOWING;
}
根據認可機構的狀態,我想讓它做不同的動作。就像球,我會更新的功能,我可以打電話給 requestAnimationFrame 有 AI 根據其狀態:
function update() {
switch (currentState) {
case State.FOLLOWING:
// Do something to follow the ball.
break;
case State.WAITING:
// Do something to wait.
break;
case State.AIMING:
// Do something to aim.
break;
}
}
下列國家是簡單的。對手移動在垂直方向的球,和 AI 過渡到等候狀態注入一些減緩反應時間。圖 15 顯示這兩個國家。
圖 15 簡單後 AI
function moveTowardsBall() {
// Move the same distance the player would move, to make it fair.
if(ball.getPosition()[1] >= ctl.getPosition()[1] + 64) {
ctl.move(distance);
} else {
ctl.move(-distance);
}
}
function update() {
switch (currentState) {
case State.FOLLOWING:
moveTowardsBall();
currentState = State.WAITING;
case State.WAITING:
setTimeout(function() {
currentState = State.FOLLOWING;
}, 400);
break;
}
}
}
中的代碼圖 15,AI 候補之間不必遵循球並等待幾秒鐘。現在將代碼添加到遊戲全更新功能:
function update(time) {
var t = time - lastUpdate;
lastUpdate = time;
ball.update(t);
ai.update();
requestAnimationFrame(update);
}
當您運行這個遊戲時,你會看到對手跟蹤球的運動 — — 不壞的 AI 在少於 30 行代碼。當然,如果對手接住球,它不會做任何事情。因此它為小時最後的絕招,時間,以處理針對國家的行動。我想要 AI 移動隨機幾次,然後火球在一個隨機的方向。圖 16 添加一個私有的函數就是這樣。將 aimAndFire 函數添加到針對 case 語句使一個功能齊全的 AI,藉以發揮。
圖 16 瞄準、 發射 AI
function repeat(cb, cbFinal, interval, count) {
var timeout = function() {
repeat(cb, cbFinal, interval, count-1);
}
if (count <= 0) {
cbFinal();
} else {
cb();
setTimeout(function() {
repeat(cb, cbFinal, interval, count-1);
}, interval);
}
}
function aimAndFire() {
// Repeat the motion action 5 to 10 times.
var numRepeats = Math.floor(5 + Math.random() * 5);
function randomMove() {
if (Math.random() > .5) {
ctl.move(-distance);
} else {
ctl.move(distance);
}
}
function randomAimAndFire() {
var d = Math.floor( Math.random() * 3 - 1 );
opponent.setAim(d);
opponent.fire();
// Finally, set the state to FOLLOWING.
currentState = State.FOLLOWING;
}
repeat(randomMove, randomAimAndFire, 250, numRepeats);
}
接近尾聲了
到目前為止,你有了正式的 Web 遊戲,在個人電腦、 智慧手機和平板電腦上工作。有許多可能的改進,對這場比賽。它看起來將在肖像模式下上一款智慧手機,例如,有點尷尬,所以你需要確保你正在拿著電話在景觀為它才能正常工作。這是遊戲開發的網頁和超越的可能性只是個小的示範。
Michael Oneppo *是一個創造性的技師和 Direct3D 團隊在微軟前程式經理。他最近的努力包括在這項技術作為首席技術官工作非營利性圖書館為所有人和探索在紐約大學電訊互動專案碩士學位。*
由於下面的技術專家,檢討這篇文章:Mohamed 阿明易卜拉欣