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 个阶段要实现的功能,请自行实现。

  源码下载:https://files.cnblogs.com/files/zjzkiss/bydr_v3.rar

posted on 2022-09-21 19:47  语风  阅读(70)  评论(0编辑  收藏  举报