当前位置: 首页 > news >正文

怎样用自己的电脑,做网站网站建设账户搭建

怎样用自己的电脑,做网站,网站建设账户搭建,wordpress和typecho,网站开发公司营业范围本文字数#xff1a;7539字 预计阅读时间#xff1a;30分钟 01 前言 说起小游戏#xff0c;最经典的莫过于飞机大战了#xff0c;相信很多同学都玩过。今天我们也来试试开发个有趣的小游戏吧#xff01;我们将从零开始#xff0c;看看怎样一步步实现一个H5版的飞机大战7539字 预计阅读时间30分钟 01 前言 说起小游戏最经典的莫过于飞机大战了相信很多同学都玩过。今天我们也来试试开发个有趣的小游戏吧我们将从零开始看看怎样一步步实现一个H5版的飞机大战 首先我们定好目标要做一个怎样的飞机大战以及去哪整游戏素材 刚好微信小程序官方提供了一个飞机大战小游戏的模板打开【微信开发者工具】选择【新建项目】-【小游戏】选择飞机大战的模板创建后就是一个小程序版飞机大战。 运行小程序之后可以看到下面的效果 从运行效果上看这个飞机大战已经比较完整包含了以下内容 1.地图滚动播放背景音效 2.玩家控制飞机移动 3.飞机持续发射子弹播放发射音效 4.随机出现向下移动的敌军 5.子弹碰撞敌军时播放爆炸动画和爆炸音效同时子弹和敌军都销毁并增加1个得分 6.飞机碰撞敌军时游戏结束弹出结束面板。 接下来我们以这个效果为参考并拷贝这个项目中的图片和音效素材从头做一个H5版飞机大战吧 02 选择游戏框架 你可能会好奇既然微信小程序官方已经生成好了完整代码直接参考那套代码不就好吗 这里就涉及到游戏框架的问题小程序那套代码是没有使用游戏框架的所以很多基础的地方都需要自己实现比如说子弹移动子弹与敌军碰撞检测等。 我们以碰撞为例在小程序项目中是这样实现的 1.先定义好碰撞检测的方法isCollideWith()通过两个物体的坐标和宽高进行碰撞检测计算 isCollideWith(sp) {let spX  sp.x  sp.width / 2;let spY  sp.y  sp.height / 2;if (!this.visible || !sp.visible) return false;return !!(spX  this.x  spX  this.x  this.width  spY  this.y  spY  this.y  this.height); }, 2.然后在每一帧的回调中遍历所有子弹和所有敌军依次调用isCollideWith()进行碰撞检测 update() {bullets.forEach((bullet)  {for (let i  0, il  enemys.length; i  il; i) {if (enemys[i].isCollideWith(bullet)) {// Do Something}}}); } 3.而通过游戏框架可能只需要一行代码。我们以Phaser为例 this.physics.add.overlap(bullets, enemys, ()  { // Do Something }, null, this); 上面代码的含义是bullets子弹组和enemys敌军组发生overlap重叠则触发回调。 从上面的例子可以看出选择一个游戏框架来开发游戏可以大大降低开发难度减少代码量。 当开发一个专业的游戏时我们一般会选择专门的游戏引擎比如CocosEgretLayaBoxUnity等。但是如果只是做一个简单的H5小游戏嵌入我们的前端项目中使用Phaser就可以了。 引用Phaser官网上的介绍 【Phaser是一个快速、免费且有趣的开源HTML5游戏框架可在桌面和移动Web浏览器上提供WebGL和Canvas渲染。可以使用第三方工具将游戏编译为iOS、Android和本机应用程序。您可以使用JavaScript或TypeScript进行开发。】 同时Phaser在社区也非常受欢迎Github上收获35.5k的StarNpm上最近一周下载量19k。 因此我们采用Phaser作为游戏框架。接下来开始正式我们的飞机大战之旅啦 03 准备工作 3.1 创建项目 项目采用的技术栈是Phaser Vue3 TypeScript Vite。 当然对于这个游戏来说核心的框架是Phaser其他都是可选的。只使用Phaser Html也是可以开发的只是我们希望采用目前更主流的开发方式。 进行工作目录直接使用vue手脚架创建名为plane-war的项目。 npm create vue 项目创建完成安装依赖检查是否运行正常。 cd plane-war npm install npm run dev 接下来再安装phaser。 npm install phaser 3.2 整理素材 接下来我们重新整理下项目清除不需要的文件并把游戏素材拷贝到assets目录最终目录结构如下 plane-war ├── src │   ├── assets │   │   ├── audio │   │   │   ├── bgm.mp3 │   │   │   ├── boom.mp3 │   │   │   └── bullet.mp3 │   │   ├── images │   │   │   ├── background.jpg │   │   │   ├── boom.png │   │   │   ├── bullet.png │   │   │   ├── enemy.png │   │   │   ├── player.png │   │   │   └── sprites.png │   │   └── json │   │       └── sprites.json │   ├── App.vue │   └── main.ts 素材处理1 原本游戏素材中爆炸动画是由19张独立图片组成在Phaser中需要合成一张雪碧图可以通过雪碧图合成工具合成命名为boom.png效果如下 素材处理2 原本游戏素材中结束面板的图片来源一张叫Common.png的雪碧图我们重命名为sprites.png。并且我们还需要为这个雪碧图制作一份说明起名为sprites.json。通过它来指定我们需要用到目标图片及其在雪碧图中的位置。 这里我们指定2个目标图片result是结束面板button是按钮。 {textures: [{image: sprites.png,size: {w: 512,h: 512},frames: [{filename: result,frame: { x: 0, y: 0, w: 119, h: 108 }},{filename: button,frame: { x: 120, y: 6, w: 39, h: 24 }}]}] } 3.3 初步运行 我们重构App.vue创建了一个游戏对象game指定父容器为#container创建成功后则会在父容器中生成一个canvas 元素游戏的所有内容都通过这个canvas进行呈现和交互。 templatediv idcontainer/div /template script setup langts import { onMounted, onUnmounted } from vue; import { Game, AUTO, Scale } from phaser;let game: Game; onMounted(() {game new Game({parent: container,type: AUTO,width: 375,// 高度依据屏幕宽高比计算height: (window.innerHeight / window.innerWidth) * 375,scale: {// 自动缩放至宽或高与父容器一致类似css中的contain// 由于宽高比与屏幕宽高比一致最终就是刚好全屏效果mode: Scale.FIT,},physics: {default: arcade,arcade: {debug: false,},},}); });onUnmounted(() {game.destroy(true); }); /script style body {margin: 0; } #app {height: 100%; } /style 通过npm run dev再次运行项目我们把浏览器展示区切换为移动设备展示此时可以看到canvas并且其宽高应该正好全屏。 3.4 场景设计 可以看到现在画布还是全黑的这是因为创建game对象时还没有接入任何场景。在Phaser中一个游戏可以包含多个场景而具体的游戏画面和交互都是在各个场景中实现的。 接下来我们设计3个场景 预载场景 加载整个游戏资源创建动画展示等待开始画面。主场景游戏的主要画面和交互。结束场景展示游戏结束画面。 在项目中我们新增3个自定义场景类 plane-war ├── src │   ├── game │   │   ├── Preloader.ts │   │   ├── Main.ts │   │   └── End.ts 自定义场景类继承Scene类包含了以下基本结构 import { Scene } from phaser;export class Preloader extends Scene {constructor() {// 场景命名这个命名在后面场景切换使用super(Preloader);}// 加载游戏资源preload() {}// preload中的资源全部加载完成后执行create() {}// 每一帧的回调update() {} } 按上面的基本结构分别实现好3个场景类并导入到game对象的创建中 import { onMounted, onUnmounted } from vue; import { Game, AUTO, Scale } from phaser; import { Preloader } from ./game/Preloader; import { Main } from ./game/Main; import { End } from ./game/End;let game: Game; onMounted(()  {game  new Game({// 其他参数省略...// 定义场景默认初始化数组中首个场景即 Preloaderscene: [Preloader, Main, End],}); }); 04 预载场景 准备工作完成后接下来我们开始真正开发第一个游戏场景预载场景对应Preloader.ts文件。 4.1 加载游戏资源 在preload方法中加载整个游戏所需的资源。 import { Scene } from phaser; import backgroundImg from ../assets/images/background.jpg; import enemyImg from ../assets/images/enemy.png; import playerImg from ../assets/images/player.png; import bulletImg from ../assets/images/bullet.png; import boomImg from ../assets/images/boom.png; import bgmAudio from ../assets/audio/bgm.mp3; import boomAudio from ../assets/audio/boom.mp3; import bulletAudio from ../assets/audio/bullet.mp3;export class Preloader extends Scene {constructor() {super(Preloader);}preload() {// 加载图片this.load.image(background, backgroundImg);this.load.image(enemy, enemyImg);this.load.image(player, playerImg);this.load.image(bullet, bulletImg);this.load.spritesheet(boom, boomImg, {frameWidth: 64,frameHeight: 48,});// 加载音频this.load.audio(bgm, bgmAudio);this.load.audio(boom, boomAudio);this.load.audio(bullet, bulletAudio);}create() {} } 4.2 添加元素 接下来我们在create()方法中去添加背景背景音乐标题开始按钮后续使用的动画并且为开始按钮绑定了点击事件。 const { width, height }  this.cameras.main; // 背景 this.add.tileSprite(0, 0, width, height, background).setOrigin(0, 0); // 背景音乐 this.sound.play(bgm);// 标题 this.add.text(width / 2, height / 4, 飞机大战, {fontFamily: Arial,fontSize: 60,color: #e3f2ed,stroke: #203c5b,strokeThickness: 6,}).setOrigin(0.5);// 开始按钮 let button  this.add.image(width / 2, (height / 4) * 3, sprites, button).setScale(3, 2).setInteractive().on(pointerdown, ()  {// 点击事件关闭当前场景打开Main场景this.scene.start(Main);});// 按钮文案 this.add.text(button.x, button.y, 开始游戏, {fontFamily: Arial,fontSize: 20,color: #e3f2ed,}).setOrigin(0.5);// 创建动画命名为 boom后面使用 this.anims.create({key: boom,frames: this.anims.generateFrameNumbers(boom, { start: 0, end: 18 }),repeat: 0, }); 运行效果如下 有个细节可以留意下就是这个背景是怎样铺满整个屏幕的 上面的代码是this.add.tileSprite()创建了一个瓦片精灵素材中的背景图就像一个一个瓦片一样铺满屏幕所以就要求素材中的背景图是一张首尾能无缝相连的图片这样就能无限平铺。主场景中的背景移动也是基于此。 05 主场景 5.1 梳理场景元素 在预载场景中点击“开始游戏”按钮可以看到画面又变成黑色此时预载场景被关闭游戏打开主场景。 在主场景中涉及到的场景元素一共有背景、玩家、子弹、敌军、爆炸我们可以先尝试把它们都渲染出来并加一些简单的动作比如移动背景子弹和敌军添加垂直方向速度播放爆炸动画等。 import { Scene, GameObjects, type Types } from phaser;// 场景元素 let background: GameObjects.TileSprite; let enemy: Types.Physics.Arcade.SpriteWithDynamicBody; let player: Types.Physics.Arcade.SpriteWithDynamicBody; let bullet: Types.Physics.Arcade.SpriteWithDynamicBody; let boom: GameObjects.Sprite;export class Main extends Scene {constructor() {super(Main);}create() {const { width, height }  this.cameras.main;// 背景background  this.add.tileSprite(0, 0, width, height, background).setOrigin(0, 0);// 玩家this.physics.add.sprite(100, 600, player).setScale(0.5);// 子弹this.physics.add.sprite(100, 500, bullet).setScale(0.25).setVelocityY(-100);// 敌军this.physics.add.sprite(100, 100, enemy).setScale(0.5).setVelocityY(100);// 爆炸this.add.sprite(200, 100, boom).play(boom);}update() {// 设置背景瓦片不断移动background.tilePositionY - 1;} } 效果如下 看起来似乎已经有了雏形但是这里还需要优化一下代码设计。我们不希望场景中的所有元素创建交互都糅合Main.ts这个文件中这样就显得有点臃肿不好维护。 我们再设计出玩家类、子弹类、敌军类、炸弹类让每个元素它们自身的事件和行为都各自去实现而主场景只负责创建它们并且处理它们之间的交互事件不需要去关心它们内部的实现。 虽然这个游戏的整体代码也不多但是通过这个设计思想可以让我们的代码设计更加合理当以后开发其他更复杂的小游戏时也可以套用这种模式。 5.2 玩家类 回顾上面的创建玩家的代码 this.physics.add.sprite(100, 600, player).setScale(0.5); 原本的代码是直接创建了一个“物理精灵对象“我们现在改成新建一个Player类这个类继承Physics.Arcade.Sprite然后在主场景中通过new Player()也同样生成物理精灵对象。相当于Player类拓展了原本Physics.Arcade.Sprite增加了对自身的一些事件处理和行为封装。后续的子弹类敌军类等也是同样的方式。 Player类主要拓展了长按移动事件具体实现如下 import { Physics, Scene } from phaser;export class Player extends Physics.Arcade.Sprite {isDown: boolean  false;downX: number;downY: number;constructor(scene: Scene) {// 创建对象let { width, height }  scene.cameras.main;super(scene, width / 2, height - 80, player);scene.add.existing(this);scene.physics.add.existing(this);// 设置属性this.setInteractive();this.setScale(0.5);this.setCollideWorldBounds(true);// 注册事件this.addEvent();}addEvent() {// 手指按下我方飞机this.on(pointerdown, ()  {this.isDown  true;// 记录按下时的飞机坐标this.downX  this.x;this.downY  this.y;});// 手指抬起this.scene.input.on(pointerup, ()  {this.isDown  false;});// 手指移动this.scene.input.on(pointermove, (pointer)  {if (this.isDown) {this.x  this.downX  pointer.x - pointer.downX;this.y  this.downY  pointer.y - pointer.downY;}});} } 5.3 子弹类 Bullet类主要拓展了发射子弹和子弹出界事件具体实现如下 import { Physics, Scene } from phaser;export class Bullet extends Physics.Arcade.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {// 创建对象super(scene, x, y, texture);scene.add.existing(this);scene.physics.add.existing(this);// 设置属性this.setScale(0.25);}// 发射子弹fire(x: number, y: number) {this.enableBody(true, x, y, true, true);this.setVelocityY(-300);this.scene.sound.play(bullet);}// 每一帧更新回调preUpdate(time: number, delta: number) {super.preUpdate(time, delta);// 子弹出界事件子弹走到顶部超出屏幕if (this.y  -14) {this.disableBody(true, true);}} } 5.4 敌军类 Enemy类主要拓展了生成敌军和敌军出界事件具体实现如下 import { Physics, Math, Scene } from phaser;export class Enemy extends Physics.Arcade.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {// 创建对象super(scene, x, y, texture);scene.add.existing(this);scene.physics.add.existing(this);// 设置属性this.setScale(0.5);}// 生成敌军born() {let x  Math.Between(30, 345);let y  Math.Between(-20, -40);this.enableBody(true, x, y, true, true);this.setVelocityY(Math.Between(150, 300));}// 每一帧更新回调preUpdate(time: number, delta: number) {super.preUpdate(time, delta);let { height }  this.scene.cameras.main;// 敌军出界事件敌军走到底部超出屏幕if (this.y  height  20) {this.disableBody(true, true)}} } 5.5 爆炸类 Boom 类主要拓展了显示爆炸和“隐藏爆炸”具体实现如下 import { GameObjects, Scene } from phaser;export class Boom extends GameObjects.Sprite {constructor(scene: Scene, x: number, y: number, texture: string) {super(scene, x, y, texture);// 爆炸动画播放结束事件this.on(animationcomplete-boom, this.hide, this);}// 显示爆炸show(x: number, y: number) {this.x  x;this.y  y;this.setActive(true);this.setVisible(true);this.play(boom);this.scene.sound.play(boom);}// 隐藏爆炸hide() {this.setActive(false);this.setVisible(false);} } 5.6 重构主场景 上面我们实现了玩家类子弹类敌军类爆炸类接下来我们在主场景中重新创建这些元素并加入分数文本元素。 import { Scene, Physics, GameObjects } from phaser; import { Player } from ./Player; import { Bullet } from ./Bullet; import { Enemy } from ./Enemy; import { Boom } from ./Boom;// 场景元素 let background: GameObjects.TileSprite; let player: Player; let enemys: Physics.Arcade.Group; let bullets: Physics.Arcade.Group; let booms: GameObjects.Group; let scoreText: GameObjects.Text;// 场景数据 let score: number;export class Main extends Scene {constructor() {super(Main);}create() {let { width, height }  this.cameras.main;// 创建背景background  this.add.tileSprite(0, 0, width, height, background).setOrigin(0, 0);// 创建玩家player  new Player(this);// 创建敌军enemys  this.physics.add.group({frameQuantity: 30,key: enemy,enable: false,active: false,visible: false,classType: Enemy,});// 创建子弹bullets  this.physics.add.group({frameQuantity: 15,key: bullet,enable: false,active: false,visible: false,classType: Bullet,});// 创建爆炸booms  this.add.group({frameQuantity: 30,key: boom,active: false,visible: false,classType: Boom,});// 分数score  0;scoreText  this.add.text(10, 10, 0, {fontFamily: Arial,fontSize: 20,});// 注册事件this.addEvent();},update() {// 背景移动background.tilePositionY - 1;} } 需要注意的是这里的子弹敌军爆炸都是按组创建的这样我们可以直接监听子弹组和敌军组的碰撞而不需要监听每一个子弹和每一个敌军的碰撞。另一方面创建组时已经把组内的元素全部创建好了比如创建敌军时指定frameQuantity: 30表示直接创建30个敌军元素后续敌军不断出现和销毁其实就是这30个元素在循环使用而已而并非源源不断地创建新元素以此减少性能损耗。 最后再把注册事件实现主场景就全部完成了。 // 注册事件 addEvent() {// 定时器this.time.addEvent({delay: 400,callback: ()  {// 生成2个敌军for (let i  0; i  2; i) {enemys.getFirstDead()?.born();}// 发射1颗子弹bullets.getFirstDead()?.fire(player.x, player.y - 32);},callbackScope: this,repeat: -1,});// 子弹和敌军碰撞this.physics.add.overlap(bullets, enemys, this.hit, null, this);// 玩家和敌军碰撞this.physics.add.overlap(player, enemys, this.gameOver, null, this); } // 子弹击中敌军 hit(bullet, enemy) {// 子弹和敌军隐藏enemy.disableBody(true, true);bullet.disableBody(true, true);// 显示爆炸booms.getFirstDead()?.show(enemy.x, enemy.y);// 分数增加scoreText.text  String(score); } // 游戏结束 gameOver() {// 暂停当前场景并没有销毁this.sys.pause();// 保存分数this.registry.set(score, score);// 打开结束场景this.game.scene.start(End); } 06 结束场景 最后再实现一下结束场景很简单主要包含结束面板得分重新开始按钮。 import { Scene } from phaser;export class End extends Scene {constructor() {super(End);}create() {let { width, height }  this.cameras.main;// 结束面板this.add.image(width / 2, height / 2, sprites, result).setScale(2.5);// 标题this.add.text(width / 2, height / 2 - 85, 游戏结束, {fontFamily: Arial,fontSize: 24,}).setOrigin(0.5);// 当前得分let score  this.registry.get(score);this.add.text(width / 2, height / 2 - 10, 当前得分${score}, {fontFamily: Arial,fontSize: 20,}).setOrigin(0.5);// 重新开始按钮let button  this.add.image(width / 2, height / 2  50, sprites, button).setScale(3, 2).setInteractive().on(pointerdown, ()  {// 点击事件关闭当前场景打开Main场景this.scene.start(Main);});// 按钮文案this.add.text(button.x, button.y, 重新开始, {fontFamily: Arial,fontSize: 20,}).setOrigin(0.5);} } 07 优化 经过上面的代码整个游戏已经基本完成。不过在测试的时候感觉玩家和敌军还存在一定距离就触发了碰撞事件。在创建game时我们可以打开debug模式这样就可以看到Phaser为我们提供的一些调试信息。 game  new Game({physics: {default: arcade,arcade: {debug: true,},},// ... }); 测试一下碰撞 可以看到两个元素的边框确实发生碰撞了但是这并不符合我们的要求我们希望两个飞机看起来是真的挨到一起才触发碰撞事件。所以我们可以再优化一下飞机本身不变但是边框缩小。 在Player.ts的构造函数中追加如下 export class Player extends Physics.Arcade.Sprite {constructor() {// ...// 追加下面一行this.body.setSize(120, 120);} } 在Enemy.ts的构造函数中追加如下 export class Enemy extends Physics.Arcade.Sprite {constructor() {// ...// 追加下面一行this.body.setSize(100, 60);} } 最终可以看到边框已经被缩小效果如下 08 结语 至此飞机大战全部开发完成。 回顾一下开发过程我们先搭建项目创建游戏对象接下来又设计了预载场景、主场景、结束场景并且为了减少主场景的复杂度我们以场景元素的维度将涉及到的场景元素进行封装形成玩家类、子弹类、敌军类、爆炸类让这些场景元素各自实现自身的事件和行为。 在Phaser中的场景元素又可以分为普通元素和物理元素物理元素是来自Physics其中玩家类子弹类敌军类都是物理元素物理元素具有物理属性比如重力速度加速度弹性碰撞等。 在本文代码中涉及到了很多Phaser的API介于篇幅没有一一解释但是很多通过字面意思也可以理解比如说disableBody表示禁用元素setVelocityY表示设置Y 轴方向速度。并且我们也可以通过编译器的代码提示功能去了解这些方法的说明和参数含义 最后本文的所有代码都已上传gitee有兴趣的同学可以拉取代码看下。 演示效果https://yuhuo.online/plane-war/点击阅读原文访问链接 源码地址https://gitee.com/yuhuo520/plane-war
http://www.hkea.cn/news/14341928/

相关文章:

  • dw中怎样做网站二级页面团员电子档案查询网
  • 网站建设实践报告3000字对网页设计作品的意见
  • 网站开发 语言net网络安全有名的培训学校
  • 互联网门户网站有哪些mip网站建设
  • ps海报制作教程步骤的网站企业的网站建设
  • 琼山网站制作罗定城乡建设规划局网站
  • 评价中国建设银行网站dede减肥网站源码
  • 网站架构图的制作免费网站建设官网
  • 网站建设 ipc备案郑州网站优化外包顾问
  • 开发网站公司排行制作公司网站多少钱
  • 信阳企业网站建设wordpress插件入门
  • 如何注册网站卖东西网站建设收获
  • 机关网站建设制度提高搜索引擎排名
  • 哪个网站可以查当地建设项目网页设计实训报告总结思考
  • 请写出网站建设的整个过程校园网站建设宣传
  • 具有价值的网站制作虚拟主机网站模板
  • 开发一个小网站多少钱wordpress在线视频插件
  • 甘肃网站建设公司网页设计入门视频
  • 岚山网站建设公司wordpress customize-support
  • 购物网站运营东莞人才网招聘
  • 国内永久免费建站汽车网站策划书
  • 网站虚假备案网站开发属于什么专业
  • 电子商务网站首页网站维护服务器
  • 如何生成自己的网站接私活做网站要不要签合同
  • 手机做网站自己做沈阳做网站优化的公司
  • 扬州网站建设制作广告
  • 购物网站开发教程 视频建网站软件
  • 工业互联网平台建设优化网站用软件好吗
  • 新建网站需要多少钱域名查询网站
  • 网页设计与网站建设中的热点是什么如何制作网站app