本文简单介绍一个小游戏:坦克大战,基于paperjs开发

图片描述

满满的压迫感。

目前该版本的基本功能:

  1. 按键控制坦克的移动,鼠标左键射击。
  2. 随机生成的NPC(enemy),自动定位player的位置,无限逼近。
  3. 炮塔能够随着鼠标方向转动。
  4. 地图边界限制,player不会越界。

效果如下:
图片描述

初始化我们的坦克

initRole() {
    const position = new paper.Point(this.WIDTH / 2, this.HEIGHT / 2)
    const end = new paper.Point(position.x, position.y - 50)
    const direction = end.subtract(position)
    this.tank = new Tank(position, 'white', direction)
},

Tank类的入参有三个,分别是随机位置,坦克颜色,以及当前随即方向。
坦克类完整代码如下:

/*
 * @Author: Hhvcg
 * @Date: 2023-03-01 14:11:32
 * @LastEditors: -_-
 * @Description: 坦克类
 */
import paper from 'paper'
import { Ammunition } from './AmmunitionDepo'
// import { getRandomColor } from '@/utils/weapons'
const SIZE = 50
export class Tank {
  constructor(position, color, direction) {
    this.color = color
    this.direction = direction
    this.path = null
    this.position = position
    this.AmmunitionDepo = []
    this.ammunitionSize = 5
    this.step = 10
    this.init()
  }
  autoRun(position) {
    this.direction = position.subtract(this.path.position).clone()
    this.updateTurret()
  }
  updateTurret() {
    const vector = this.direction.normalize(50).clone()
    const vector_end = this.path.children['base'].position.add(vector).clone()
    const turret = this.path.children['turret']
    turret.replaceWith(new paper.Path(
      {
        name: 'turret',
        segments: [this.path.children['base'].position, vector_end],
        strokeWidth: 5,
        strokeColor: this.color,
        strokeCap: 'round'
      }
    ))
    this.path.position = this.path.position.add(this.direction.normalize()).clone()
  }
  init() {
    this.path = new paper.Group({
      children: [
        new paper.Path.Rectangle({
          name: 'base',
          center: this.position,
          size: new paper.Size(SIZE),
          strokeColor: this.color
        }),
        new paper.Path({
          name: 'turret',
          segments: [this.position, this.position.add(this.direction)],
          strokeWidth: 5,
          strokeColor: this.color,
          strokeCap: 'round'

        }),
        new paper.Path.Circle({
          radius: SIZE / 4,
          center: this.position,
          fillColor: this.color
        })
      ]
    })
  }
  judeBoundary(position, width, height) {
    if (position.x <= 0 || position.x >= width || position.y <= 0 || position.y >= height) {
      return true
    } else {
      return false
    }
  }
  // 根据方向命令改变tank位置
  handleChangePosition(e, width, height) {
    let newP = null
    if (e.key === 'left' || e.key === 'a') {
      newP = new paper.Point(this.path.position.x - this.step, this.path.position.y)
    } else if (e.key === 'right' || e.key === 'd') {
      newP = new paper.Point(this.path.position.x + this.step, this.path.position.y)
    } else if (e.key === 'up' || e.key === 'w') {
      newP = new paper.Point(this.path.position.x, this.path.position.y - this.step)
    } else if (e.key === 'down' || e.key === 's') {
      newP = new paper.Point(this.path.position.x, this.path.position.y + this.step)
    }
    if (!this.judeBoundary(newP, width, height)) {
      this.path.position = newP
      this.position = this.path.position
    }
    newP = null
  }
  fire() {
    const ammunition = new Ammunition(this.position, 'circle', 5, 'orange')
    this.AmmunitionDepo.push(ammunition)
  }
  update(order) {
  }
}

很简单的一个角色类,需要注意的是,NPC也是由这个类生成。然后我们只需要在每帧时刻,改变其位置即可。目前每个NPC的方向默认就是只想Player,主要是为了营造一种开头那种压迫感
下一回中,我们要添加的功能如下:

  1. 让npc路径正常化
  2. 炮塔发射炮弹时,加一个顿挫感,显得真实些
  3. 最后也是比较重要的,光打炮没效果可不行
  4. 坦克自身炮管的多样化。我们可能不仅仅只有一种单管炮,也可以设计出一些类似天启坦克的那种双管。