<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # DevOps and Game Dev with GitLab CI/CD > 原文:[https://docs.gitlab.com/ee/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/](https://docs.gitlab.com/ee/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/) * [The game](#the-game) * [Requirements and setup](#requirements-and-setup) * [Continuous Integration](#continuous-integration) * [Build your game with GitLab CI/CD](#build-your-game-with-gitlab-cicd) * [Test your game with GitLab CI/CD](#test-your-game-with-gitlab-cicd) * [Run your CI/CD pipeline](#run-your-cicd-pipeline) * [Continuous Deployment](#continuous-deployment) * [Set up S3 Bucket](#set-up-s3-bucket) * [Set up AWS Secrets](#set-up-aws-secrets) * [Deploy your game with GitLab CI/CD](#deploy-your-game-with-gitlab-cicd) * [Conclusion](#conclusion) * [Further settings](#further-settings) # DevOps and Game Dev with GitLab CI/CD[](#devops-and-game-dev-with-gitlab-cicd "Permalink") 隨著 WebGL 和 WebSockets 的進步,瀏覽器作為游戲開發平臺非常可行,而無需使用 Adobe Flash 之類的插件. 此外,通過使用 GitLab 和[AWS](https://aws.amazon.com/) ,單個游戲開發人員以及游戲開發團隊可以輕松地在線托管基于瀏覽器的游戲. 在本教程中,我們將專注于 DevOps,以及使用[GitLab CI / CD](../../README.html)使用持續集成/部署方法測試和托管游戲. 我們假設您熟悉 GitLab,JavaScript 和游戲開發的基礎知識. ## The game[](#the-game "Permalink") 我們的[演示游戲](http://gitlab-game-demo.s3-website-us-east-1.amazonaws.com/)由一個簡單的太空飛船組成,該太空飛船通過在給定方向上單擊鼠標進行射擊. 在開發另一款游戲[Dark Nova](https://www.darknova.io)的開始時,創建強大的 CI / CD 流水線對于團隊工作的快速節奏至關重要. 本教程將以我[之前的介紹性文章為基礎,](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/)并執行以下步驟: 1. 使用上一篇文章中的代碼開始由 gulp 文件構建的準[相位](https://phaser.io)游戲 2. 添加和運行單元測試 3. 創建可以觸發以給定方向生成`Bullet`的`Weapon`類 4. 添加使用此武器并在屏幕上四處移動的`Player`類 5. 添加我們將用于`Player`和`Weapon`的精靈 6. 使用持續集成和持續部署方法進行測試和部署 到最后,我們將擁有一個[可玩游戲](http://gitlab-game-demo.s3-website-us-east-1.amazonaws.com/)的核心,該[游戲](http://gitlab-game-demo.s3-website-us-east-1.amazonaws.com/)在每次推送到[代碼庫](https://gitlab.com/blitzgren/gitlab-game-demo) `master`分支時都經過測試和部署. 這還將提供樣板代碼,用于啟動具有以下組件的基于瀏覽器的游戲: * 用[TypeScript](https://s0www0typescriptlang0org.icopy.site/)和[PhaserJs 編寫](https://phaser.io) * 使用[Gulp](https://gulpjs.com)構建,運行和測試 * [Chai](https://www.chaijs.com)和[Mocha 的](https://s0mochajs0org.icopy.site/)單元測試 * 使用 GitLab 進行 CI / CD * 在 GitLab.com 上托管代碼庫 * 在 AWS 上托管游戲 * 部署到 AWS ## Requirements and setup[](#requirements-and-setup "Permalink") 請參考我以前的文章[DevOps 和 Game Dev,](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/)以學習基礎開發工具,運行類似于 Hello World 的游戲,以及從每次新推手到使用 GitLab CI / CD 來構建此游戲. 此游戲[存儲庫](https://gitlab.com/blitzgren/gitlab-game-demo)的`master`分支包含具有所有配置的完整版本. 如果您想繼續閱讀本文,可以從`devops-article`分支進行克隆并進行工作: ``` git clone git@gitlab.com:blitzgren/gitlab-game-demo.git git checkout devops-article ``` 接下來,我們將創建一小部分測試,以舉例說明我希望該`Weapon`類經歷的大多數狀態. 首先,創建一個名為`lib/tests`的文件夾,并將以下代碼添加到一個新文件`weaponTests.ts` : ``` import { expect } from 'chai'; import { Weapon, BulletFactory } from '../lib/weapon'; describe('Weapon', () => { var subject: Weapon; var shotsFired: number = 0; // Mocked bullet factory var bulletFactory: BulletFactory = <BulletFactory>{ generate: function(px, py, vx, vy, rot) { shotsFired++; } }; var parent: any = { x: 0, y: 0 }; beforeEach(() => { shotsFired = 0; subject = new Weapon(bulletFactory, parent, 0.25, 1); }); it('should shoot if not in cooldown', () => { subject.trigger(true); subject.update(0.1); expect(shotsFired).to.equal(1); }); it('should not shoot during cooldown', () => { subject.trigger(true); subject.update(0.1); subject.update(0.1); expect(shotsFired).to.equal(1); }); it('should shoot after cooldown ends', () => { subject.trigger(true); subject.update(0.1); subject.update(0.3); // longer than timeout expect(shotsFired).to.equal(2); }); it('should not shoot if not triggered', () => { subject.update(0.1); subject.update(0.1); expect(shotsFired).to.equal(0); }); }); ``` 為了使用`gulpfile.js`構建和運行這些測試,我們還要將以下`gulpfile.js`函數添加到現有的`gulpfile.js`文件中: ``` gulp.task('build-test', function () { return gulp.src('src/tests/**/*.ts', { read: false }) .pipe(tap(function (file) { // replace file contents with browserify's bundle stream file.contents = browserify(file.path, { debug: true }) .plugin(tsify, { project: "./tsconfig.test.json" }) .bundle(); })) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true}) ) .pipe(gulp.dest('built/tests')); }); gulp.task('run-test', function() { gulp.src(['./built/tests/**/*.ts']).pipe(mocha()); }); ``` 我們將開始實施游戲的第一部分,并通過這些`Weapon`測試. `Weapon`類將公開一種方法,以給定的方向和速度觸發子彈的生成. 稍后,我們將實現一個`Player`類,將用戶輸入綁定在一起以觸發武器. 在`src/lib`文件夾中,創建一個`weapon.ts`文件. 我們將添加兩個類: `Weapon`和`BulletFactory` ,它們將封裝 Phaser 的**sprite**和**group**對象,以及游戲特定的邏輯. ``` export class Weapon { private isTriggered: boolean = false; private currentTimer: number = 0; constructor(private bulletFactory: BulletFactory, private parent: Phaser.Sprite, private cooldown: number, private bulletSpeed: number) { } public trigger(on: boolean): void { this.isTriggered = on; } public update(delta: number): void { this.currentTimer -= delta; if (this.isTriggered && this.currentTimer <= 0) { this.shoot(); } } private shoot(): void { // Reset timer this.currentTimer = this.cooldown; // Get velocity direction from player rotation var parentRotation = this.parent.rotation + Math.PI / 2; var velx = Math.cos(parentRotation); var vely = Math.sin(parentRotation); // Apply a small forward offset so bullet shoots from head of ship instead of the middle var posx = this.parent.x - velx * 10 var posy = this.parent.y - vely * 10; this.bulletFactory.generate(posx, posy, -velx * this.bulletSpeed, -vely * this.bulletSpeed, this.parent.rotation); } } export class BulletFactory { constructor(private bullets: Phaser.Group, private poolSize: number) { // Set all the defaults for this BulletFactory's bullet object this.bullets.enableBody = true; this.bullets.physicsBodyType = Phaser.Physics.ARCADE; this.bullets.createMultiple(30, 'bullet'); this.bullets.setAll('anchor.x', 0.5); this.bullets.setAll('anchor.y', 0.5); this.bullets.setAll('outOfBoundsKill', true); this.bullets.setAll('checkWorldBounds', true); } public generate(posx: number, posy: number, velx: number, vely: number, rot: number): Phaser.Sprite { // Pull a bullet from Phaser's Group pool var bullet = this.bullets.getFirstExists(false); // Set the few unique properties about this bullet: rotation, position, and velocity if (bullet) { bullet.reset(posx, posy); bullet.rotation = rot; bullet.body.velocity.x = velx; bullet.body.velocity.y = vely; } return bullet; } } ``` 最后,我們將重做我們的入口點`game.ts` ,將`Player`和`Weapon`對象綁定在一起,并將它們添加到更新循環中. 這是更新的`game.ts`文件的外觀: ``` import { Player } from "./player"; import { Weapon, BulletFactory } from "./weapon"; window.onload = function() { var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameCanvas', { preload: preload, create: create, update: update }); var player: Player; var weapon: Weapon; // Import all assets prior to loading the game function preload () { game.load.image('player', 'assets/player.png'); game.load.image('bullet', 'assets/bullet.png'); } // Create all entities in the game, after Phaser loads function create () { // Create and position the player var playerSprite = game.add.sprite(400, 550, 'player'); playerSprite.anchor.setTo(0.5); player = new Player(game.input, playerSprite, 150); var bulletFactory = new BulletFactory(game.add.group(), 30); weapon = new Weapon(bulletFactory, player.sprite, 0.25, 1000); player.loadWeapon(weapon); } // This function is called once every tick, default is 60fps function update() { var deltaSeconds = game.time.elapsedMS / 1000; // convert to seconds player.update(deltaSeconds); weapon.update(deltaSeconds); } } ``` 運行`gulp serve` ,您可以四處奔跑射擊. 精彩! 讓我們更新 CI 管道,使其包括運行測試以及現有的構建作業. ## Continuous Integration[](#continuous-integration "Permalink") 為了確保我們的更改不會破壞構建并且所有測試仍然通過,我們利用持續集成(CI)來為每次推送自動運行這些檢查. 通讀本文以了解[持續集成,持續交付和持續部署](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) ,以及 GitLab 如何利用這些方法. 在上[一教程中,](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/)我們已經設置了一個`.gitlab-ci.yml`文件,用于從每次推送開始構建我們的應用程序. 我們需要設置一個新的 CI 作業進行測試,GitLab CI / CD 將使用我們從 gulp 生成的工件在構建作業后運行. 請通讀[CI / CD 配置](../../../ci/yaml/README.html)文件[上](../../../ci/yaml/README.html)的[文檔,](../../../ci/yaml/README.html)以探索其內容并根據需要進行調整. ### Build your game with GitLab CI/CD[](#build-your-game-with-gitlab-cicd "Permalink") 我們需要更新構建作業以確保測試也能運行. 將`gulp build-test`添加到現有`build`作業的`script`數組的末尾. 一旦這些命令運行,我們就知道需要訪問 GitLab CI / CD `artifacts`提供的`built`文件夾中的所有內容. 我們還將緩存`node_modules`以避免不得不完全重新拉動那些依賴項:只需將它們打包在緩存中即可. 這是完整的`build`工作: ``` build: stage: build script: - npm i gulp -g - npm i - gulp - gulp build-test cache: policy: push paths: - node_modules artifacts: paths: - built ``` ### Test your game with GitLab CI/CD[](#test-your-game-with-gitlab-cicd "Permalink") 對于本地測試,我們只需要運行`gulp run-tests` ,這需要像`build`作業一樣在全球范圍內安裝 gulp. 我們從緩存中拉出`node_modules` ,因此`npm i`命令不必做太多事情. 在準備部署時,我們知道我們仍然需要工件中的`built`文件夾,該文件夾將作為上一個作業的默認行為被帶入. 最后,按照慣例,我們通過給 GitLab CI / CD 一個`test` [階段](../../../ci/yaml/README.html#stages)來告知需要在`build`工作之后運行它. 按照 YAML 結構, `test`作業應如下所示: ``` test: stage: test script: - npm i gulp -g - npm i - gulp run-test cache: policy: push paths: - node_modules/ artifacts: paths: - built/ ``` 我們為以指定間隔射擊的`Weapon`類添加了單元測試. `Player`類實現了`Weapon`以及四處移動和射擊的能力. 此外,我們還使用`.gitlab-ci.yml`在 GitLab CI / CD 管道中添加了測試工件和測試階段,從而使我們能夠在每次推送時運行測試. 現在,我們整個`.gitlab-ci.yml`文件應如下所示: ``` image: node:10 build: stage: build script: - npm i gulp -g - npm i - gulp - gulp build-test cache: policy: push paths: - node_modules/ artifacts: paths: - built/ test: stage: test script: - npm i gulp -g - npm i - gulp run-test cache: policy: pull paths: - node_modules/ artifacts: paths: - built/ ``` ### Run your CI/CD pipeline[](#run-your-cicd-pipeline "Permalink") 而已! 添加所有新文件,提交并推送. 有關此時存儲庫外觀的參考,請參考[示例存儲庫中與本文相關](https://gitlab.com/blitzgren/gitlab-game-demo/commit/8b36ef0ecebcf569aeb251be4ee13743337fcfe2)的[最終提交](https://gitlab.com/blitzgren/gitlab-game-demo/commit/8b36ef0ecebcf569aeb251be4ee13743337fcfe2) . 通過同時應用構建和測試階段,GitLab 將在每次推送到我們的存儲庫時按順序運行它們. 如果一切順利,您將在管道的每個作業上得到一個綠色的復選標記: [![Passing Pipeline](https://img.kancloud.cn/fd/f8/fdf82b1e5a612aab5f7bfcf4a967fbc1_816x277.png)](img/test_pipeline_pass.png) 您可以通過單擊`test`作業以輸入完整的構建日志來確認測試通過. 滾動到底部,觀察所有過去的榮耀: ``` $ gulp run-test [18:37:24] Using gulpfile /builds/blitzgren/gitlab-game-demo/gulpfile.js [18:37:24] Starting 'run-test'... [18:37:24] Finished 'run-test' after 21 ms Weapon ? should shoot if not in cooldown ? should not shoot during cooldown ? should shoot after cooldown ends ? should not shoot if not triggered 4 passing (18ms) Uploading artifacts... built/: found 17 matching files Uploading artifacts to coordinator... ok id=17095874 responseStatus=201 Created token=aaaaaaaa Job succeeded ``` ## Continuous Deployment[](#continuous-deployment "Permalink") 我們在每次推送時都構建并測試了代碼庫. 為了完成持續部署的全部流程,讓我們[使用 AWS S3](https://aws.amazon.com/free/)設置[免費的 Web 托管,](https://aws.amazon.com/free/)并通過一項工作來部署構建工件. GitLab 還提供了免費的靜態站點托管服務[GitLab Pages](https://about.gitlab.com/stages-devops-lifecycle/pages/) ,但是 Dark Nova 特別使用需要使用`AWS S3`其他 AWS 工具. 通讀本文,該文章描述了[如何同時部署到 S3 和 GitLab 頁面,](https://about.gitlab.com/blog/2016/08/26/ci-deployment-and-environments/)并且比本文討論的內容更深入地研究 GitLab CI / CD 的原理. ### Set up S3 Bucket[](#set-up-s3-bucket "Permalink") 1. 登錄您的 AWS 賬戶并轉到[S3](https://console.aws.amazon.com/s3/home) 2. 點擊頂部的**創建存儲桶**鏈接 3. 輸入您選擇的名稱,然后單擊下一步 4. 保留默認**屬性** ,然后單擊下一步 5. 單擊" **管理組"權限** ,然后為" **所有人"**組允許" **讀取** ",單擊"下一步". 6. 創建存儲桶,然后在您的 S3 存儲桶列表中選擇它 7. 在右側,單擊" **屬性"**并啟用" **靜態網站托管"**類別 8. Update the radio button to the **使用此存儲桶托管網站** selection. Fill in `index.html` and `error.html` respectively ### Set up AWS Secrets[](#set-up-aws-secrets "Permalink") 我們需要能夠使用我們的 AWS 賬戶憑證部署到 AWS,但是我們當然不希望在源代碼中添加機密信息. 幸運的是,GitLab 通過[Variables](../../../ci/variables/README.html)提供了解決方案. 由于[IAM](https://aws.amazon.com/iam/)管理,這可能會變得復雜. 作為最佳實踐,您不應使用根安全憑證. 正確的 IAM 憑據管理不在本文討論范圍之內,但是 AWS 會提醒您,不建議使用 root 憑據,并且應該違反其最佳做法. 隨意遵循最佳實踐并使用自定義 IAM 用戶的憑據,這將是兩個相同的憑據(密鑰 ID 和密鑰). 充分了解[AWS 中的 IAM 最佳做法](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)是一個好主意. 我們需要將以下憑據添加到 GitLab: 1. 登錄您的 AWS 賬戶并轉到[安全憑證頁面](https://console.aws.amazon.com/iam/home#/security_credential) 2. 單擊**訪問密鑰**部分,然后**創建新的訪問密鑰** . 創建密鑰并保留 ID 和秘密,以后需要它們 [![AWS Access Key Configuration](https://img.kancloud.cn/3e/fb/3efb29f98cd8a47c52d57934ec40af36_781x392.png)](img/aws_config_window.png) 3. 轉到您的 GitLab 項目,單擊左側欄中的**設置> CI / CD** . 4. 展開**變量**部分 [![GitLab Secret Config](https://img.kancloud.cn/d3/df/d3df9fa0d0818a88acece765496b6a7a_965x572.png)](img/gitlab_config.png) 5. 添加一個名為`AWS_KEY_ID`的密鑰,并將步驟 2 中的密鑰 ID 復制到" **值"**字段中 6. 添加一個名為`AWS_KEY_SECRET`的密鑰,并將步驟 2 中的密鑰機密復制到" **值"**字段中 ### Deploy your game with GitLab CI/CD[](#deploy-your-game-with-gitlab-cicd "Permalink") 要部署構建工件,我們需要在 Shared Runner 上安裝[AWS CLI](https://aws.amazon.com/cli/) . Shared Runner 還需要能夠通過您的 AWS 賬戶進行身份驗證以部署工件. 按照約定,AWS CLI 將尋找`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY` . GitLab 的 CI 為我們提供了一種使用`deploy`作業的`variables`部分傳遞在上一節中設置的`variables`的方法. 最后,我們添加指令以確保`only`在推送到`master`時進行部署. 這樣,每個分支仍然通過 CI 運行,并且只有合并(或直接提交)到 master 才會觸發管道的`deploy`工作. 將它們放在一起可獲得以下內容: ``` deploy: stage: deploy variables: AWS_ACCESS_KEY_ID: "$AWS_KEY_ID" AWS_SECRET_ACCESS_KEY: "$AWS_KEY_SECRET" script: - apt-get update - apt-get install -y python3-dev python3-pip - easy_install3 -U pip - pip3 install --upgrade awscli - aws s3 sync ./built s3://gitlab-game-demo --region "us-east-1" --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --cache-control "no-cache, no-store, must-revalidate" --delete only: - master ``` 確保在最后一個腳本命令中更新區域和 S3 URL 以適合您的設置. 我們的最終配置文件`.gitlab-ci.yml`看起來像: ``` image: node:10 build: stage: build script: - npm i gulp -g - npm i - gulp - gulp build-test cache: policy: push paths: - node_modules/ artifacts: paths: - built/ test: stage: test script: - npm i gulp -g - gulp run-test cache: policy: pull paths: - node_modules/ artifacts: paths: - built/ deploy: stage: deploy variables: AWS_ACCESS_KEY_ID: "$AWS_KEY_ID" AWS_SECRET_ACCESS_KEY: "$AWS_KEY_SECRET" script: - apt-get update - apt-get install -y python3-dev python3-pip - easy_install3 -U pip - pip3 install --upgrade awscli - aws s3 sync ./built s3://gitlab-game-demo --region "us-east-1" --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --cache-control "no-cache, no-store, must-revalidate" --delete only: - master ``` ## Conclusion[](#conclusion "Permalink") 在[演示存儲庫中,](https://gitlab.com/blitzgren/gitlab-game-demo)您還可以找到一些樣板代碼來使[TypeScript](https://s0www0typescriptlang0org.icopy.site/) , [Mocha](https://s0mochajs0org.icopy.site/) , [Gulp](https://gulpjs.com/)和[Phaser](https://phaser.io)與 GitLab CI / CD 完美地結合在一起,這是在制作[Dark Nova 時](https://www.darknova.io)汲取的教訓的結果. 使用免費和開源軟件的組合,我們擁有完整的 CI / CD 流水線,游戲基礎和單元測試,所有這些操作和部署都可以在每次熟練掌握的情況下完成-只需很少的代碼. 可以通過 GitLab 的構建日志輕松調試錯誤,并且在成功提交后的幾分鐘內,您就可以在游戲中實時看到更改. 借助 Dark Nova 從一開始就設置持續集成和持續部署可實現快速而穩定的開發. 我們可以輕松地在單獨的[環境中](../../environments/index.html)測試更改,如果需要,可以在多個環境中測試更改. 平衡和更新多人游戲可能會持續且乏味,但是相信使用 GitLab CI / CD 進行穩定部署會在快速獲得玩家更改方面有很大的喘息空間. ## Further settings[](#further-settings "Permalink") 以下是一些可以進一步研究的想法,可以加快或改善您的流程: * [紗線](https://yarnpkg.com)代替 npm * 設置可以預加載依賴項和工具(如 AWS CLI)的自定義[Docker](../../../ci/docker/using_docker_images.html#define-image-and-services-from-gitlab-ciyml)映像 * 將[自定義域](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)轉發到游戲的 S3 靜態網站 * 如果您發現小型項目不必要,請合并工作 * 避免排隊,并設置自己的[自定義 GitLab CI / CD 運行器](https://about.gitlab.com/blog/2016/03/01/gitlab-runner-with-docker/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看