4.3. 编程实现
(续上)
3. 实现射击捕鱼
在第 3 个阶段,将按照“编程思路”中介绍的射击捕鱼的算法进行编程,实现让玩家操控大炮射击捕鱼。在“bydr”项目目录中,把version2.jl复制一份并命名为version3.jl,然后在第2个版本的基础上编写第3个版本的代码。
1) 创建3个角色
由于GameZero没有精灵(sprite)的概念,所以我们将game_sprites.jl,改名为game_actor.jl,并在其中分别创建BulletSprite()函数生成炮弹角色、NetSprite()函数生成渔网角色和CoinSprite()函数生成硬币角色。
BulletSprite()函数代码如下:
1 function BulletSprite(x,y) 2 #'''炮弹精灵''' 3 actor=Actor(bullet_img) 4 actor.pos=x,y 5 actor.speed = 300 6 actor.alpha=255 7 #self.visible = True 8 return actor 9 end
炮弹角色有两个属性:speed 和 visible,分别用于控制炮弹的移动速度和可见状态。不过GameZero的Actor没有visible属性,但是提供了alpha属性,这个属性可以控制Actor的透明度,alpha的值为0表示完全透明,255表示完全不透明,因此可以用这个属性达到控制炮弹可见性的目的。
另外创建函数fire_move()法用于实现炮弹的移动,当炮弹移动到游戏窗口的可见区域之外,就让其消失。
1 function fire_move(bullet::Actor, dt) 2 #移动炮弹 3 if bullet.alpha==255 4 move(bullet,bullet.speed * dt) 5 if bullet.x < 0 || bullet.x > 1024 || bullet.y > 768 6 #self.visible = False 7 bullet.alpha=0 8 end 9 end 10 end
NetSprite()函数代码如下:
1 function NetSprite(netPos) 2 #'''渔网精灵''' 3 actor=Actor(fishing_net_img,pos=netPos) 4 #self.set_sprite_center() 5 actor.size = 0 6 #actor.visible = True 7 actor.alpha=255 8 return actor 9 end
渔网角色两个属性:size 和 visible,分别用于控制渔网张开的大小和可见性。可见性鱼炮弹类同。
另外,创建open()函数,用于实现让渔网由小慢慢变大并消失的动态效果。
function open(net::Actor, dt) #打开渔网 if net.scale <= [1,1] net.size += 300 * dt net.scale = [net.size / 100,net.size / 100] else #net.visible = false net.alpha=0 end end
注意Actor的属性scale,可对角色图像进行缩放,它是个含有两个元素的数组,分别为横向和纵向缩放比例,因此它可以非等比缩放。
CoinSprite()函数的代码如下:
1 function CoinSprite(coinPos, score=0) 2 #'''硬币精灵''' 3 #println(silver_coin_img[1]) 4 actor=Actor(silver_coin_img[1],pos=coinPos) 5 actor.score = score 6 actor.speed = 400 7 #actor.visible = True 8 actor.alpha=255 9 actor.frame=1 10 actor.set_animation=coin_animation(score,actor) 11 #面向窗口底部的硬币箱 12 point(actor,160, 597) 13 return actor 14 end
硬币角色有3个属性,Score用于记录捕获一条鱼的得分,speed和visible分别用于控制硬币移动速度和可见状态。类中的 set_animation属性用于按得分创建银币或金币的动画图像。
这里就显现出Julia的独特之处了!在Julia中处处皆对象。函数也是对象,因此可以将一个函数作为某个对象的属性。这里,硬币的set_animation属性就被赋予了一个函数
actor.set_animation=coin_animation(score,actor)
而coin_animation()函数是这样的:
function coin_animation(score,coin::Actor) #'''设置硬币动画''' images = (score <= 20) ? silver_coin_img : gold_coin_img function _animation() _frame=coin.frame if _frame < length(images) coin.image = images[_frame] _frame += 1 else _frame = 1 end coin.frame=_frame schedule_once(_animation, 1/16) end return _animation end
另外,创建move_down()函数,控制硬币的移动,当硬币移动到计分牌下方时,消失。
function move_down(coin::Actor, dt) #'''移动硬币''' if coin.y < 600 move(coin,coin.speed * dt) else #coin.visible = False #println(coin.alpha) coin.alpha=0 end end
2) 控制射击捕鱼动
切换到“version3.jl”源文件,创建fire_control()函数,用于实现发射炮弹捕鱼,检测炮弹与鱼的碰撞,以及控制渔网张开、硬币落下等。
function fire_control(dt)…end
从 bullets 列表读取各个炮弹精灵实例,让炮弹精灵移动,并与 fishes 列表中的每个鱼角色实例进行碰撞检测。当炮弹角色碰到鱼角色时,就让炮弹消失,并在鱼的位置抛出一张渔网。此外,还从 bullets 列表中移除处于不可见状态的炮弹角色实例。
1 #'''捕鱼控制''' 2 #炮弹 3 for bullet in bullets 4 if bullet.alpha==255 5 #移动炮弹 6 fire_move(bullet,dt) 7 if bullet.y < 150 8 continue 9 end 10 #对每条有生命的鱼进行碰撞检测 11 for fish in fishes 12 if fish.life <= 0 13 continue 14 end 15 if collide(bullet,fish) 16 #命中鱼减去生命值 17 fish.life -= 1 18 #让炮弹消失 19 #bullet.visible = False 20 bullet.alpha=0 21 #抛撒渔网在炮弹处 22 throw_fishing_net(fish.pos) 23 end 24 end 25 else 26 #delete!(bullets,bullet) 27 #bullets.remove(bullet) 28 #bullet.delete() 29 filter!(e->e≠bullet,bullets) 30 end 31 end
从 nets 列表中读取各个渔网角色实例,让渔网逐渐张开。当渔网角色处于不可见状态时,就将其从 nets 列表中移除。
#渔网 for net in nets if net.alpha==255 open(net,dt) else #delete!(nets,net) #nets.remove(net) #net.delete() filter!(e->e≠net,nets) end end
从 coins 列表中读取各个硬币角色实例,让硬币角色向着窗口左下角的硬币盒处移动。 之后 ,将捕鱼的得分累加到全局变量 Score 中 ,并将硬币角色从 coins 列表中移除。
global score_label #硬币 for coin in coins if coin.alpha==255 move_down(coin,dt) else #加分 global score score += coin.score score_label = TextActor(@sprintf("%06d",score),"Arial-Black",font_size=24, color=Int[255,255,255,255]) score_label.pos=(165,635) #score_label.text = '%06d' % score #delete!(coins,coin) #coins.remove(coin) #coin.delete() filter!(e->e≠coin,coins) end end
至此,函数 fire_contro1( )编写完毕,在窗口update事件方法里调用。
接下来,创建fire_bullet()、throw_fishing_net()和 release_coin()这3 个函数,分别用于实现发射炮弹、抛出渔网和释放硬币的功能。在这些函数中将会生成炮弹角色、渔网角色和硬币角色的实例,将它们加人到对应的bullets、nets或coins列表中。
function fire_bullet() #'''发射炮弹''' #println(cannon.angle) bullet = BulletSprite(0,0) bullet.angle = cannon.angle bullet.x=cannon.x+ (cannon.w-bullet.w)/2 bullet.y=cannon.y+ (cannon.h-bullet.h)/2 push!(bullets,bullet) #bullets.append(bullet) end function throw_fishing_net(pos) #'''抛撒渔网''' net = NetSprite(pos) push!(nets,net) #nets.append(net) end function release_coin(pos, score) #'''释放金币''' coin = CoinSprite(pos, score) coin.set_animation() #coin_animation(coin,score) push!(coins,coin) #coins.append(coin) end
在游戏窗口中按下鼠标左键时,将调用 fire_bullet() 函数发射炮弹。
function on_mouse_down(g::Game, pos, button) if button==MouseButtons.LEFT #println("在窗口'$pos'处按下左键") fire_bullet() end end
还要在游戏窗口的事件draw()方法中调用 draw_actor()函数,将 nets、coins和bullets 这 3 个列表中的渔网、硬币和炮弹角色实例的图像绘制到窗口中。
function draw(g::Game)
clear()
draw_actor(fishes)
draw_actor(nets)
draw_actor(coins)
draw(panel)
draw(score_label)
draw_actor(bullets)
draw(cannon)
end
至此,这个游戏程序的第3个版本完成。运行程序,就能让玩家操控大炮发射炮弹捕鱼了。赶快试试吧!
4. 播放背景音乐
看着赏心悦目的画面,再配上悦耳动听的音乐,将让游戏体验更佳。这是第 4 个阶段要实现的功能,请自行实现。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!