鸿蒙HarmonyOS5简易的动作射击思路
这篇文章介绍了一个基于Canvas的太空射击游戏实现方案,主要包括:1. 游戏框架设计,使用ArkUI组件管理游戏状态;2. 核心功能实现,包括玩家控制、敌人生成、碰撞检测和游戏循环;3. 视觉元素绘制,使用Canvas绘制星空背景、飞船、敌人和子弹;4. 交互设计,提供触摸和键盘两种控制方式。游戏采用动态难度系统,随着得分提高会加快敌人生成速度,并包含三种不同属性的敌人类型。该方案展示了鸿蒙系统
设计思路
使用Canvas绘制游戏场景
实现玩家控制、敌人自动生成和移动
添加射击功能和碰撞检测
设计游戏状态管理(开始、进行中、结束)
// GamePage.ets
@Entry
@Component
struct GamePage {
@State gameStatus: string = 'ready' // ready, playing, gameover
@State score: number = 0
@State lives: number = 3
private context: CanvasRenderingContext2D | null = null
private player: Player = new Player()
private enemies: Enemy[] = []
private bullets: Bullet[] = []
private gameWidth: number = 0
private gameHeight: number = 0
private lastTime: number = 0
private enemySpawnCooldown: number = 500 // 敌人生成间隔(ms)
private lastSpawnTime: number = 0
private backgroundY: number = 0 // 背景星空的Y位置
// 控制方向
moveLeft: boolean = false
moveRight: boolean = false
shoot: boolean = false
private lastShootTime: number = 0
private shootCooldown: number = 300 // 射击冷却时间
// 初始化Canvas
initCanvas(context: CanvasRenderingContext2D, width: number, height: number) {
this.context = context
this.gameWidth = width
this.gameHeight = height
this.player.x = width / 2
this.player.y = height - 100
// 开始游戏
startGame() {
this.gameStatus = 'playing'
this.score = 0
this.lives = 3
this.enemies = []
this.bullets = []
this.player.x = this.gameWidth / 2
this.player.y = this.gameHeight - 100
this.gameLoop()
// 游戏主循环
gameLoop() {
if (this.gameStatus !== 'playing') return
const currentTime = new Date().getTime()
const elapsed = this.lastTime ? currentTime - this.lastTime : 16
this.lastTime = currentTime
this.update(elapsed)
this.draw()
requestAnimationFrame(() => this.gameLoop())
// 更新游戏状态
update(elapsed: number) {
// 更新背景位置(产生移动效果)
this.backgroundY += 0.2 * elapsed
// 玩家移动
if (this.moveLeft) this.player.x -= this.player.speed * elapsed / 16
if (this.moveRight) this.player.x += this.player.speed * elapsed / 16
// 边界限制
if (this.player.x < 30) this.player.x = 30
if (this.player.x > this.gameWidth - 30) this.player.x = this.gameWidth - 30
// 处理射击
if (this.shoot && (currentTime - this.lastShootTime) > this.shootCooldown) {
this.bullets.push(new Bullet(
this.player.x,
this.player.y,
4,
10,
'#FFFF00'
))
this.lastShootTime = currentTime
// 生成敌人
if ((currentTime - this.lastSpawnTime) > this.enemySpawnCooldown) {
this.spawnEnemy()
this.lastSpawnTime = currentTime
// 更新敌人位置
this.enemies.forEach((enemy, index) => {
enemy.y += enemy.speed * elapsed / 16
// 超出屏幕移除
if (enemy.y > this.gameHeight) {
this.enemies.splice(index, 1)
})
// 更新子弹位置
this.bullets.forEach((bullet, index) => {
bullet.y -= bullet.speed * elapsed / 16
// 超出屏幕移除
if (bullet.y < 0) {
this.bullets.splice(index, 1)
})
// 碰撞检测 - 子弹与敌人
for (let i = this.bullets.length - 1; i >= 0; i--) {
for (let j = this.enemies.length - 1; j >= 0; j--) {
const bullet = this.bullets[i]
const enemy = this.enemies[j]
if (this.checkCollision(bullet, enemy)) {
// 移除碰撞的子弹和敌人
this.bullets.splice(i, 1)
this.enemies.splice(j, 1)
this.score += 100
// 增加游戏难度
if (this.score > 0 && this.score % 500 === 0) {
this.enemySpawnCooldown = Math.max(100, this.enemySpawnCooldown - 50)
break
}
// 碰撞检测 - 玩家与敌人
for (let i = this.enemies.length - 1; i >= 0; i--) {
const enemy = this.enemies[i]
if (this.checkCollision(this.player, enemy)) {
this.enemies.splice(i, 1)
this.lives -= 1
if (this.lives <= 0) {
this.gameStatus = 'gameover'
break
}
// 碰撞检测算法
checkCollision(obj1: GameObject, obj2: GameObject): boolean {
const dx = obj1.x - obj2.x
const dy = obj1.y - obj2.y
const distance = Math.sqrt(dx dx + dy dy)
return distance < (obj1.radius + obj2.radius)
// 生成敌人
spawnEnemy() {
const types = [
speed: 0.2, radius: 15, color: '#FF5252', score: 100 }, // 红色敌人
speed: 0.15, radius: 20, color: '#7C4DFF', score: 200 }, // 紫色敌人
speed: 0.3, radius: 10, color: '#00E676', score: 150 }, // 绿色敌人
const type = types[Math.floor(Math.random() * types.length)]
const enemy = new Enemy(
Math.random() * (this.gameWidth - 40) + 20,
-20,
type.speed,
type.radius,
type.color
)
this.enemies.push(enemy)
// 绘制游戏场景
draw() {
if (!this.context) return
const ctx = this.context
const width = this.gameWidth
const height = this.gameHeight
// 绘制背景
ctx.fillStyle = '#000020'
ctx.fillRect(0, 0, width, height)
// 绘制星空背景
ctx.fillStyle = '#FFFFFF'
for (let i = 0; i < 100; i++) {
const starX = Math.random() * width
const starY = (Math.random() * height + this.backgroundY) % height
ctx.fillRect(starX, starY, 1.5, 1.5)
// 绘制玩家
ctx.fillStyle = this.player.color
ctx.beginPath()
ctx.moveTo(this.player.x, this.player.y - 20)
ctx.lineTo(this.player.x - 15, this.player.y + 15)
ctx.lineTo(this.player.x + 15, this.player.y + 15)
ctx.closePath()
ctx.fill()
// 绘制敌人
this.enemies.forEach(enemy => {
ctx.fillStyle = enemy.color
ctx.beginPath()
ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2)
ctx.fill()
// 敌人的"眼睛"
ctx.fillStyle = '#000'
ctx.beginPath()
ctx.arc(enemy.x - 5, enemy.y - 5, 4, 0, Math.PI * 2)
ctx.arc(enemy.x + 5, enemy.y - 5, 4, 0, Math.PI * 2)
ctx.fill()
})
// 绘制子弹
this.bullets.forEach(bullet => {
ctx.fillStyle = bullet.color
ctx.beginPath()
ctx.arc(bullet.x, bullet.y, bullet.radius, 0, Math.PI * 2)
ctx.fill()
})
// 绘制UI
ctx.fillStyle = '#FFFFFF'
ctx.font = '20px sans-serif'
ctx.fillText(分数: ${this.score}, 20, 40)
ctx.fillText(生命: ${this.lives}, 20, 70)
// 游戏结束界面
if (this.gameStatus === 'gameover') {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'
ctx.fillRect(0, 0, width, height)
ctx.fillStyle = '#FFFFFF'
ctx.font = 'bold 36px sans-serif'
ctx.textAlign = 'center'
ctx.fillText('游戏结束', width / 2, height / 2 - 30)
ctx.font = '30px sans-serif'
ctx.fillText(最终分数: ${this.score}, width / 2, height / 2 + 30)
ctx.textAlign = 'start'
else if (this.gameStatus === 'ready') {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'
ctx.fillRect(0, 0, width, height)
ctx.fillStyle = '#FFFFFF'
ctx.font = 'bold 36px sans-serif'
ctx.textAlign = 'center'
ctx.fillText('太空射击游戏', width / 2, height / 2 - 60)
ctx.font = '24px sans-serif'
ctx.fillText('控制:左下按钮移动,右下按钮射击', width / 2, height / 2)
ctx.font = '30px sans-serif'
ctx.fillText('点击开始游戏', width / 2, height / 2 + 60)
ctx.textAlign = 'start'
}
build() {
Column() {
// 游戏画布区域
Stack({ alignContent: Alignment.Bottom }) {
// 游戏画布
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#000000')
.onReady(() => {
this.context = this.context.getContext('2d') as CanvasRenderingContext2D
const width = px2vp(this.context.width)
const height = px2vp(this.context.height)
this.initCanvas(this.context, width, height)
})
.onTouch((e) => {
if (e.type = TouchType.Down && this.gameStatus = 'ready') {
this.startGame()
})
// 控制按钮区域
Row() {
// 左移按钮
Button('←')
.onClick(() => this.moveLeft = true)
.onTouch((e) => {
if (e.type === TouchType.Down) this.moveLeft = true
else if (e.type === TouchType.Up) this.moveLeft = false
})
.width('33%')
.fontSize(30)
.backgroundColor('#555555')
// 右移按钮
Button('→')
.onClick(() => this.moveRight = true)
.onTouch((e) => {
if (e.type === TouchType.Down) this.moveRight = true
else if (e.type === TouchType.Up) this.moveRight = false
})
.width('33%')
.fontSize(30)
.backgroundColor('#555555')
// 射击按钮
Button('射击')
.onClick(() => this.shoot = true)
.onTouch((e) => {
if (e.type === TouchType.Down) this.shoot = true
else if (e.type === TouchType.Up) this.shoot = false
})
.width('34%')
.fontSize(30)
.backgroundColor('#FF0000')
.width('100%')
.height(60)
.backgroundColor('#333333')
.width('100%')
.height('100%')
.width('100%')
.height('100%')
.onKeyEvent((e) => {
// 键盘控制,方便模拟器使用
if (e.keyCode === 1004) { // 左箭头
if (e.action === 0) this.moveLeft = true
else if (e.action === 1) this.moveLeft = false
else if (e.keyCode === 1003) { // 右箭头
if (e.action === 0) this.moveRight = true
else if (e.action === 1) this.moveRight = false
else if (e.keyCode === 1000) { // 空格
if (e.action === 0) this.shoot = true
else if (e.action === 1) this.shoot = false
})
}
// 游戏对象基类
class GameObject {
x: number
y: number
speed: number
radius: number
color: string
constructor(x: number, y: number, speed: number, radius: number, color: string) {
this.x = x
this.y = y
this.speed = speed
this.radius = radius
this.color = color
}
// 玩家类
class Player extends GameObject {
constructor() {
super(0, 0, 0.35, 15, '#4FC3F7')
}
// 敌人类
class Enemy extends GameObject {
// 子弹类
class Bullet extends GameObject {
代码解析
游戏结构
GamePage组件:游戏的入口组件,包含所有游戏逻辑和渲染
Canvas画布:负责绘制游戏场景中的所有元素
控制按钮:实现玩家飞船的左右移动和射击功能
核心类
GameObject:所有游戏对象的基类
Player:玩家飞船类
Enemy:敌人类
Bullet:子弹类
关键功能实现
游戏循环:使用requestAnimationFrame实现流畅的游戏循环
碰撞检测:采用圆形边界检测算法,高效准确
背景绘制:动态星空背景增加场景感
难度递增:随着得分增加,敌人生成频率提高
游戏状态管理:开始、进行中、游戏结束三种状态
控制方式
触摸控制:左下按钮移动,右下按钮射击
键盘支持:模拟器可使用方向键和空格键(开发阶段实用)
触摸事件响应:区分按下和抬起动作实现更自然控制
游戏特点
三种不同属性的敌人:不同颜色、大小和移动速度
生命值系统:玩家有3条生命
动态难度:随着分数提高,敌人生成速度增加
美观的UI:包括分数显示、生命指示器等
使用说明
在开发环境中创建一个ArkUI项目
将代码复制到GamePage.ets文件中
添加必要的样式和配置
在模拟器或设备上运行
这个简单的射击游戏展示了鸿蒙游戏开发的基本思路,包括图形渲染、状态管理、用户交互等核心功能。
更多推荐



所有评论(0)