【坦克大战】vue

前言

接着上篇讲,本篇主要给大家讲解一下子弹击中物体、物体销毁、敌方坦克构建生成、运动算法、爆炸效果、以及障碍物的生成;了解了这些我相信你可以不依赖游戏引擎实现大部分小游戏的开发。

Es5版本: 在线游戏icon-default.png?t=N7T8https://www.zhoumingjie.com/Battle-of-tank/battle%20city/index.html 源代码icon-default.png?t=N7T8https://github.com/mingjiezhou/Battle-of-tank

W/上 S/下 A/左 D/右 F/射击

让我们开始吧!

敌方坦克的生成

我们可以使用 for 循环和Tank 构造函数,批量制造多个敌方坦克,x,y 为其在画布中的坐标,direction 为坦克当前方向,type 为精灵图中截取坦克图片的信息,包含了坐标,尺寸,类型等

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

for(let t=0; t<20; t++) {

  let tank = new Tank(new TankConfig({

    x: 100 + t*30,

    y: 100,

    direction: DIRECTION.DOWN,

    type: TANK_TYPE.ENEMY0,

    is_player: 0

  }))

  tank.star();

}

ENEMY0: {

  type: 'ENEMY1',

  dimension: [30, 30],

  image_coordinates: [129, 1, 129, 33]

}

坦克移动的算法

emove 函数就是就是物体移动状态下每帧都会执行的函数,将根据当前方向修改下帧的坐标,当下帧坐标到达地图边缘时将执行 dir 函数更新坦克方向,如果是子弹则将销毁。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

this.emove = function (d, obstacle_sprites) {

    this.direction = d

    switch (d) {

      case DIRECTION.UP:

        if (

          (obstacle_sprites && !this.checkRangeOverlap(obstacle_sprites)) ||

          !obstacle_sprites

        ) {

          this.y -= this.speed

     

          if (this.y <= 10) {

            this.dir()

          }

        } else {

          this.dir()

        }

        break

    ...

dir 函数用来随机修改移动的方向,当然这个函数不能每帧都调用,否则坦克将像无头苍蝇一样了;那么什么时候需要修改方向呢,我们认为当坦克和物体相撞的时候或者到达地图边缘时修改方向是合理的;子弹也可以认为是一个物体,所以子弹到达坦克周边一定距离时也将引起坦克规避动作,也就是将触发dir 函数。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

this.dir = function () {

    if(Math.floor(Math.random()*10) === 0 || Math.floor(Math.random()*10) === 1) {

      this.direction = DIRECTION.UP;

    };

    if(Math.floor(Math.random()*10) === 2 || Math.floor(Math.random()*10) === 3) {

      this.direction = DIRECTION.DOWN;

    };

    if(Math.floor(Math.random()*10) === 4 || Math.floor(Math.random()*10) === 5) {

      this.direction = DIRECTION.LEFT;

    };

    if(Math.floor(Math.random()*10) === 6 || Math.floor(Math.random()*10) === 7) {

      this.direction = DIRECTION.RIGHT;

    };

    if(Math.floor(Math.random()*10) === 8 || Math.floor(Math.random()*10) === 9) {

      this.dir();

    }

}

子弹击中物体的算法

我们定义 checkRangeOverlap 函数来判断两个物体是否相撞,uiobjs 为画布中所有的元素对象列表,包含 坦克、子弹、障碍物等;

this.getFrontPoints() 函数将根据当前方向返回包含三个顶端点坐标数组,形成判断区域;

uiobjs[o].getCornerPoints() 函数返回当前元素的四个边角坐标数组,形成判断区域;

然后getFrontPoints() 的三个点坐标 将分别和 uiobjs[o].getCornerPoints() 的四边坐标进行点对点判断,根据x, y 数值满足下方四个条件时则认为此点坐标在元素内部。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// 判断点坐标是否在区域内部,以识别是否相撞

 CanvasSprite.prototype.checkRangeOverlap = function (uiobjs) {

   for (let o in uiobjs) {

     let obstacle_cp = uiobjs[o].getCornerPoints()

     let fp = this.getFrontPoints()

     for (let idx = 0; idx < fp.length; idx++) {

       if (

         fp[idx].x > obstacle_cp[0].x &&

         fp[idx].x < obstacle_cp[1].x &&

         fp[idx].y > obstacle_cp[0].y &&

         fp[idx].y < obstacle_cp[2].y

       ) {

         return true

       }

     }

   }

   return false

 }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 返回当前物体顶端三坐标

  CanvasSprite.prototype.getFrontPoints = function () {

    let front_point

    switch (this.direction) {

      case DIRECTION.UP:

        front_point = [

          new Point(this.x, this.y),

          new Point((2 * this.x + this.width) / 2, this.y),

          new Point(this.x + this.width, this.y),

        ]

        break

      ... 缩略,下左右方向

    }

    return front_point

  }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// 返回元素四边坐标形成的矩形区域范围

  CanvasSprite.prototype.getCornerPoints = function () {

    var corner_points

    switch (this.direction) {

      case DIRECTION.UP:

        corner_points = [

          new Point(this.x, this.y),

          new Point(this.x + this.width, this.y),

          new Point(this.x + this.width, this.y + this.height),

          new Point(this.x, this.y + this.height),

        ]

        break

        ... 缩略,下左右方向

    }

    return corner_points

  }

啊 坦克搞多了!但是可以看到子弹击中效果是成功的,你发现了没,击中后有一个爆炸效果,这个是怎么实现的呢?

爆炸效果的实现

当识别到击中后将此坦克将触发explode 爆炸效果,然后每帧 判断 isDestroied 是否销毁,后续每帧将 explosion_count++ 从 0 到 5,然后更改alive 状态为0 代表已销毁。

1

2

3

4

5

6

7

8

9

10

11

12

if (s instanceof Tank && s.alive && s.isDestroied()) {

    s.explode()

}

this.isDestroied = function () {

    return explosion_count > 0

  }

   

this.explode = function () {

    if (explosion_count++ === 5) {

      this.alive = 0

    }

  }

然后 explosion_count 的数值,从0 到 5 代表爆炸效果图的5帧

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

this.getImg = function () {

  if (explosion_count > 0) {

    return {

      width: TANK_EXPLOSION_FRAME[explosion_count].dimension[0],

      height: TANK_EXPLOSION_FRAME[explosion_count].dimension[1],

      offset_x: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[0],

      offset_y: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[1],

    }

  } else {

    return {

      width: width,

      height: height,

      offset_x: this.type.image_coordinates[0],

      offset_y: this.type.image_coordinates[1],

    }

  }

}

到现在我们的坦克游戏已经基本可玩了,只不过现在是一片大平原,毫无遮拦,我们该为画布增加一些障碍物如墙体,石头等,增加游戏可玩性。

生成障碍物(石墙、砖墙等)

有了之前tanke 和 子弹的构建函数,现在这个 Block 就简单多了,只需要定义好基本的信息,如坐标,宽高、状态、方向,然后借用 apply 来使用 CanvasSprite 上的通用方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

let Block = function (x, y, direction, type) {

  type = type || BLOCK_TYPE.BLOCK_BRICK

  let alive = 1

  let width = type.dimension[0]

  let height = type.dimension[1]

  let explosion_count = 0

  this.type = type

  this.x = x

  this.y = y

  this.genre = 'block'

  this.direction = direction || DIRECTION.UP

  CanvasSprite.apply(this, [

    {

      alive: 1,

      border_y: HEIGHT,

      border_x: WIDTH,

      speed: 0,

      direction: direction,

      x: x,

      y: y,

      width: width,

      height: height,

    },

  ])

  this.isDestroied = function () {

    return explosion_count > 0

  }

  this.explode = function () {

    if (explosion_count++ === 5) {

      this.alive = 0

    }

  }

  this.getImg = function () {

    if (explosion_count > 0) {

      return {

        width: TANK_EXPLOSION_FRAME[explosion_count].dimension[0],

        height: TANK_EXPLOSION_FRAME[explosion_count].dimension[1],

        offset_x: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[0],

        offset_y: TANK_EXPLOSION_FRAME[explosion_count].image_coordinates[1],

      }

    } else {

      return {

        width: width,

        height: height,

        offset_x: type.image_coordinates[0],

        offset_y: type.image_coordinates[1],

      }

    }

  }

  this._generateId = function () {

    return uuidv4()

  }

  sprites[this._generateId()] = this

}

定义好后,使用时只需批量生成Block 的实例,将坐标,类型等信息传递进去就可以在下一帧渲染出来。

1

2

3

4

5

for(let i=0; i<=2; i++) {

  for(let j=0; j<=2; j++) {

    let block = new Block(j*16, 140 + i*16, DIRECTION.UP, BLOCK_TYPE.BLOCK_STONE)

  }

}

好了我们看看最终的效果吧!

总结

ok 坦克大战基本上完成了,你可以修改子弹发射速度,敌方坦克数量,障碍物也可以自己随意画,可玩性还是挺好的,当然还有很多细节可以完善,如 预制几种不同的地图,做成通关类,预制几条生命等。如果你想试一下,可以 star 下 github 仓库自己来改造自己的坦克大战吧。

以上就是Vue3+Canvas实现坦克大战游戏(二)的详细内容,更多关于Vue3 Canvas坦克大战的资料请关注脚本之家其它相关文章!

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很高兴回答你的问题!要使用Java基于Spring Boot框架加上TypeScript基于Vue 3.0框架来编写坦克大战游戏,你可以按照以下步骤进行: 1. 创建后端项目: - 使用Spring Initializr创建一个新的Spring Boot项目。 - 添加所需的依赖,如Spring Web和Spring WebSocket,这些将用于处理游戏逻辑和与前端通信。 2. 创建前端项目: - 使用Vue CLI创建一个新的Vue 3.0项目。 - 安装Vue Router和Vuex等必要的依赖,以便管理路由和状态。 3. 设计游戏逻辑: - 定义坦克和其他游戏元素的数据结构,如位置、方向和生命值等。 - 实现游戏规则和逻辑,包括玩家和敌人的移动、碰撞检测、射击等。 4. 实现后端功能: - 创建WebSocket端点,用于与前端进行实时通信。 - 处理前端发送的游戏操作请求,并将结果广播给所有连接的客户端。 5. 实现前端功能: - 创建游戏场景和画布,用于显示游戏元素。 - 使用Canvas API绘制坦克、子弹和其他游戏元素。 - 使用WebSocket与后端建立连接并接收游戏状态更新。 6. 联调并测试: - 启动后端和前端项目。 - 确保前后端正常通信,游戏状态能够实时同步。 - 测试游戏各项功能,如移动、射击、碰撞等。 这个过程中可能会涉及到更多的细节和技术选择,但这个步骤将为你提供一个基本的框架来实现坦克大战游戏。祝你编写愉快!如果你有任何进一步的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值