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

Go语言Ebiten坦克大战

下载依赖

 go get github.com/hajimehoshi/ebiten/v2

package mainimport ("image/color""math/rand""strconv""time""github.com/hajimehoshi/ebiten/v2""github.com/hajimehoshi/ebiten/v2/ebitenutil""github.com/hajimehoshi/ebiten/v2/inpututil"
)const (screenWidth  = 640screenHeight = 480tankSize     = 32bulletSize   = 4wallSize     = 32
)// 方向定义
const (Up = iotaRightDownLeft
)// 坦克结构
type Tank struct {x, y          float64dx, dy        float64direction     intspeed         float64isPlayer      boolshootCooldown time.DurationlastShot      time.Time
}// 子弹结构
type Bullet struct {x, y   float64dx, dy float64active boolowner  *Tank
}// 墙体结构
type Wall struct {x, y         float64destructible bool
}// 爆炸效果
type Explosion struct {x, y      float64radius    float64maxRadius float64active    bool
}// 游戏状态
type Game struct {player     *Tankenemies    []*Tankbullets    []*Bulletwalls      []*Wallexplosions []*Explosionscore      intgameOver   bool
}// 初始化游戏
func NewGame() *Game {g := &Game{bullets:    make([]*Bullet, 0, 10),enemies:    make([]*Tank, 0, 5),walls:      make([]*Wall, 0),explosions: make([]*Explosion, 0),}// 创建玩家坦克g.player = &Tank{x:             screenWidth / 2,y:             screenHeight - tankSize*2,direction:     Up,speed:         2.0,isPlayer:      true,shootCooldown: 500 * time.Millisecond,}// 创建墙壁g.createWalls()// 创建初始敌人g.spawnEnemies(3)return g
}// 创建墙壁
func (g *Game) createWalls() {// 边界墙for x := 0; x < screenWidth; x += wallSize {g.walls = append(g.walls, &Wall{x: float64(x), y: 0, destructible: false})g.walls = append(g.walls, &Wall{x: float64(x), y: screenHeight - wallSize, destructible: false})}for y := wallSize; y < screenHeight-wallSize; y += wallSize {g.walls = append(g.walls, &Wall{x: 0, y: float64(y), destructible: false})g.walls = append(g.walls, &Wall{x: screenWidth - wallSize, y: float64(y), destructible: false})}// 随机内部墙壁rand.Seed(time.Now().UnixNano())for i := 0; i < 70; i++ {x := float64(rand.Intn(screenWidth/wallSize-2)*wallSize + wallSize)y := float64(rand.Intn(screenHeight/wallSize-2)*wallSize + wallSize)// 避免玩家初始位置有墙if x > g.player.x-tankSize*2 && x < g.player.x+tankSize*2 &&y > g.player.y-tankSize*2 && y < g.player.y+tankSize*2 {continue}destructible := rand.Float64() < 0.7 // 70%可破坏墙g.walls = append(g.walls, &Wall{x: x, y: y, destructible: destructible})}
}// 生成敌人
func (g *Game) spawnEnemies(count int) {for i := 0; i < count; i++ {x := float64(rand.Intn(screenWidth/tankSize-4)*tankSize + tankSize*2)y := float64(rand.Intn(screenHeight/tankSize-6)*tankSize + tankSize*2)enemy := &Tank{x:             x,y:             y,direction:     Down,speed:         1.0,isPlayer:      false,shootCooldown: 1500 * time.Millisecond,}g.enemies = append(g.enemies, enemy)}
}// 发射子弹
func (g *Game) shoot(t *Tank) {now := time.Now()if now.Sub(t.lastShot) < t.shootCooldown {return}t.lastShot = nowb := &Bullet{owner:  t,active: true,}// 根据坦克方向设置子弹初始位置和速度switch t.direction {case Up:b.x = t.x + tankSize/2 - bulletSize/2b.y = t.yb.dy = -5.0case Right:b.x = t.x + tankSizeb.y = t.y + tankSize/2 - bulletSize/2b.dx = 5.0case Down:b.x = t.x + tankSize/2 - bulletSize/2b.y = t.y + tankSizeb.dy = 5.0case Left:b.x = t.xb.y = t.y + tankSize/2 - bulletSize/2b.dx = -5.0}g.bullets = append(g.bullets, b)
}// 创建爆炸效果
func (g *Game) createExplosion(x, y float64) {g.explosions = append(g.explosions, &Explosion{x:         x,y:         y,radius:    2,maxRadius: 20,active:    true,})
}// 检查碰撞
func checkCollision(x1, y1, w1, h1, x2, y2, w2, h2 float64) bool {return x1 < x2+w2 &&x1+w1 > x2 &&y1 < y2+h2 &&y1+h1 > y2
}// 更新游戏状态
func (g *Game) Update() error {if g.gameOver {// 游戏结束后按R键重新开始if inpututil.IsKeyJustPressed(ebiten.KeyR) {*g = *NewGame()}return nil}// 玩家控制g.handlePlayerInput()// 更新玩家位置g.updateTankPosition(g.player)// 敌人AI和更新g.updateEnemies()// 更新子弹g.updateBullets()// 更新爆炸效果g.updateExplosions()// 检查是否所有敌人都被消灭if len(g.enemies) == 0 {g.spawnEnemies(5) // 生成新一轮敌人}return nil
}// 处理玩家输入
func (g *Game) handlePlayerInput() {// 重置移动方向g.player.dx = 0g.player.dy = 0// 方向控制if ebiten.IsKeyPressed(ebiten.KeyUp) || ebiten.IsKeyPressed(ebiten.KeyW) {g.player.direction = Upg.player.dy = -g.player.speed} else if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) {g.player.direction = Rightg.player.dx = g.player.speed} else if ebiten.IsKeyPressed(ebiten.KeyDown) || ebiten.IsKeyPressed(ebiten.KeyS) {g.player.direction = Downg.player.dy = g.player.speed} else if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {g.player.direction = Leftg.player.dx = -g.player.speed}// 射击控制if ebiten.IsKeyPressed(ebiten.KeySpace) {g.shoot(g.player)}
}// 更新坦克位置(包括碰撞检测)
func (g *Game) updateTankPosition(t *Tank) {// 保存当前位置用于碰撞检测失败时恢复oldX, oldY := t.x, t.y// 移动坦克t.x += t.dxt.y += t.dy// 边界碰撞检测if t.x < 0 {t.x = 0} else if t.x+tankSize > screenWidth {t.x = screenWidth - tankSize}if t.y < 0 {t.y = 0} else if t.y+tankSize > screenHeight {t.y = screenHeight - tankSize}// 墙壁碰撞检测collided := falsefor _, w := range g.walls {if checkCollision(t.x, t.y, tankSize, tankSize, w.x, w.y, wallSize, wallSize) {collided = truebreak}}// 坦克之间的碰撞检测for _, e := range g.enemies {if t != e && checkCollision(t.x, t.y, tankSize, tankSize, e.x, e.y, tankSize, tankSize) {collided = truebreak}}// 如果发生碰撞,恢复到原来的位置if collided {t.x, t.y = oldX, oldY}
}// 更新敌人
func (g *Game) updateEnemies() {// 随机改变敌人方向和射击for _, e := range g.enemies {// 随机改变方向if rand.Float64() < 0.01 { // 1%概率改变方向e.direction = rand.Intn(4)switch e.direction {case Up:e.dx, e.dy = 0, -e.speedcase Right:e.dx, e.dy = e.speed, 0case Down:e.dx, e.dy = 0, e.speedcase Left:e.dx, e.dy = -e.speed, 0}}// 随机射击if rand.Float64() < 0.002 { // 0.2%概率射击g.shoot(e)}// 更新敌人位置g.updateTankPosition(e)}
}// 更新子弹
func (g *Game) updateBullets() {// 过滤掉不活跃的子弹activeBullets := make([]*Bullet, 0, len(g.bullets))for _, b := range g.bullets {if !b.active {continue}// 移动子弹b.x += b.dxb.y += b.dy// 检查是否超出屏幕if b.x < 0 || b.x > screenWidth || b.y < 0 || b.y > screenHeight {b.active = falsecontinue}// 检查是否击中墙壁wallHit := falsefor i, w := range g.walls {if w.destructible && checkCollision(b.x, b.y, bulletSize, bulletSize, w.x, w.y, wallSize, wallSize) {// 创建爆炸效果g.createExplosion(w.x+wallSize/2, w.y+wallSize/2)// 移除被击中的墙g.walls = append(g.walls[:i], g.walls[i+1:]...)b.active = falsewallHit = truebreak} else if !w.destructible && checkCollision(b.x, b.y, bulletSize, bulletSize, w.x, w.y, wallSize, wallSize) {// 击中不可破坏的墙g.createExplosion(b.x, b.y)b.active = falsewallHit = truebreak}}if wallHit {continue}// 检查是否击中坦克if b.owner.isPlayer {// 玩家子弹击中敌人for i, e := range g.enemies {if checkCollision(b.x, b.y, bulletSize, bulletSize, e.x, e.y, tankSize, tankSize) {g.createExplosion(e.x+tankSize/2, e.y+tankSize/2)b.active = false// 移除被击中的敌人g.enemies = append(g.enemies[:i], g.enemies[i+1:]...)g.score += 100 // 加分break}}} else {// 敌人子弹击中玩家if checkCollision(b.x, b.y, bulletSize, bulletSize, g.player.x, g.player.y, tankSize, tankSize) {g.createExplosion(g.player.x+tankSize/2, g.player.y+tankSize/2)b.active = falseg.gameOver = true // 游戏结束break}}if b.active {activeBullets = append(activeBullets, b)}}g.bullets = activeBullets
}// 更新爆炸效果
func (g *Game) updateExplosions() {activeExplosions := make([]*Explosion, 0, len(g.explosions))for _, e := range g.explosions {if !e.active {continue}// 增大爆炸半径e.radius += 1.5// 如果爆炸达到最大半径,标记为不活跃if e.radius >= e.maxRadius {e.active = false} else {activeExplosions = append(activeExplosions, e)}}g.explosions = activeExplosions
}// 绘制游戏
func (g *Game) Draw(screen *ebiten.Image) {// 填充背景色screen.Fill(color.RGBA{30, 30, 30, 255})// 绘制墙壁for _, w := range g.walls {var wallColor color.RGBA // 注意这里的正确语法if w.destructible {wallColor = color.RGBA{0, 128, 0, 255} // 绿色可破坏墙} else {wallColor = color.RGBA{128, 0, 0, 255} // 红色不可破坏墙}ebitenutil.DrawRect(screen, w.x, w.y, wallSize, wallSize, wallColor)}// 绘制玩家坦克ebitenutil.DrawRect(screen, g.player.x, g.player.y, tankSize, tankSize, color.RGBA{0, 0, 255, 255}) // 蓝色玩家坦克// 绘制坦克炮管g.drawCannon(screen, g.player)// 绘制敌人坦克for _, e := range g.enemies {ebitenutil.DrawRect(screen, e.x, e.y, tankSize, tankSize, color.RGBA{255, 0, 0, 255}) // 红色敌人坦克g.drawCannon(screen, e)}// 绘制子弹for _, b := range g.bullets {ebitenutil.DrawRect(screen, b.x, b.y, bulletSize, bulletSize, color.White)}// 绘制爆炸效果for _, e := range g.explosions {// 绘制渐变爆炸效果for r := 1.0; r <= e.radius; r += 2 {alpha := uint8(255 * (1 - r/e.maxRadius))c := color.RGBA{255, 165, 0, alpha} // 橙色爆炸ebitenutil.DrawCircle(screen, e.x, e.y, r, c)}}// 绘制分数ebitenutil.DebugPrint(screen, "Score: "+strconv.Itoa(g.score))// 如果游戏结束,显示游戏结束信息if g.gameOver {ebitenutil.DebugPrintAt(screen, "GAME OVER", screenWidth/2-50, screenHeight/2)ebitenutil.DebugPrintAt(screen, "Press R to restart", screenWidth/2-80, screenHeight/2+20)}
}// 绘制坦克炮管
func (g *Game) drawCannon(screen *ebiten.Image, t *Tank) {// 炮管颜色cannonColor := color.RGBA{200, 200, 200, 255}// 炮管位置和大小var cx, cy, cw, ch float64switch t.direction {case Up:cx = t.x + tankSize/2 - 2cy = t.y - 8cw = 4ch = 12case Right:cx = t.x + tankSize - 4cy = t.y + tankSize/2 - 2cw = 12ch = 4case Down:cx = t.x + tankSize/2 - 2cy = t.y + tankSize - 4cw = 4ch = 12case Left:cx = t.x - 8cy = t.y + tankSize/2 - 2cw = 12ch = 4}ebitenutil.DrawRect(screen, cx, cy, cw, ch, cannonColor)
}// 布局设置
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {return screenWidth, screenHeight
}func main() {ebiten.SetWindowSize(screenWidth, screenHeight)ebiten.SetWindowTitle("坦克大战")// 初始化随机数生成器rand.Seed(time.Now().UnixNano())game := NewGame()if err := ebiten.RunGame(game); err != nil {panic(err)}
}

http://www.dtcms.com/a/319369.html

相关文章:

  • ADC常用库函数(STC8系列)
  • 现代制冷系统核心技术解析:从四大件到智能控制的关键突破
  • 客户管理系统的详细项目框架结构
  • 从房地产企业运作观企业能力建设
  • (第八期)VS Code 网页开发入门指南:从零开始掌握前端开发工具
  • Leetcode——菜鸟笔记2(移动0)
  • 92. 反转链表 II
  • 【实时Linux实战系列】实时分布式计算架构的实现
  • DataEase官方出品丨SQLBot:基于大模型和RAG的智能问数系统
  • 机柜指示灯识别误报率↓85%:陌讯多模态融合算法实战解析
  • Linux 内核:节点创建汇总
  • NFS 服务器
  • 【运维进阶】NFS 服务器
  • 16.Home-懒加载指令优化
  • .NET 10 新增功能系列文章5——C# 14 中的新增功能
  • latex in overleaf快速通关论文排版
  • E频段无线射频链路为5G网络提供高容量回程解决方案 — 第一部分
  • Linux(17)——Linux进程信号(下)
  • 【RabbitMQ面试精讲 Day 14】Federation插件与数据同步
  • 剑指offer第2版——面试题1:赋值运算符函数
  • 《常见高频算法题 Java 解法实战精讲(2):堆栈与递归》
  • 【RabbitMQ面试精讲 Day 15】RabbitMQ故障转移与数据恢复
  • Java快速入门:包(Package)与导包(import)详解
  • PyTorch LSTM文本生成
  • VC6800智能相机:赋能智能制造,开启AI视觉新纪元
  • 一个设备或系统能够同时管理和监控两个摄像头的配
  • 基于Python+Vue+Mysql实现(物联网)智能大棚
  • Linux文件操作与用户管理
  • 【数据结构——并查集】
  • 第一个vue应用