找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7329|回复: 1

[教程] 如何在RenPy中做一个飞镖小游戏?

[复制链接]
发表于 2020-3-4 00:13:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 立笔犊 于 2020-3-4 00:26 编辑

     如题。
     依然是给《罗曼圣诞探案集》做的飞镖。
     演示效果如下:
      演示视频.zip (104.65 KB, 下载次数: 55)

     具体要求如下:
     1、模拟扔飞镖手抖的效果,飞镖发射前会不断晃动。
     2、飞镖扔中镖盘的不同位置得分不同,具体分数写在了最外圈上,并且外圈红色2倍,内圈红色3倍。

     这是用RenPy中的用户自定义可视组件实现的,需要看完相关renpy文档、有一定python面向对象基础并尝试过才可能完全理解。

一、写一个飞镖类Dart继承可视组件renpy.Displayable类,按文档中的要求重写几个父类方法,再暴露几个函数接口,实例化出对象my_dart。
[RenPy] 纯文本查看 复制代码
init python:
    import math,random,time,pygame
    from threading import Timer
    class Dart(renpy.Displayable):
        def __init__(self, child, **kwargs):
            # 向renpy.Displayable构造器传入额外的特性(property)。
            super(Dart, self).__init__(**kwargs)

            # 子组件。
            self.child = renpy.displayable(child)
            # 子组件的宽度和高度。
            self.width = 0
            self.height = 0

            ###与位置有关的参数###
                # 靶心的位置
            self.aim_x = 639
            self.aim_y = 249
                # 飞镖当前实际的位置
            self.x = 639
            self.y = 250

            ###与震动有关的参数###
            self.tiny_time = 0.04   # 多久刷新一次位置,越大刷新得越快
            self.d_default = 6      # 每次刷新的默认偏移量,越大默认误差越大
            self.d_mouse = 2        # 鼠标偏移量,越大鼠标的影响越大

            ###与记分有关的参数###
            self.score = 0          # 所得的分数

            # 飞镖当前是否开始运动
            self.shaking = False

        def render(self, width, height, st, at):
            """可视组件的渲染函数,用于刷新组件的显示"""
            render = renpy.Render(width,height)
            render.place(self.child, self.x, self.y,width,height)
            return render

        def event(self, ev, x, y, st):
            """不需要事件,但是继承必须重写"""
            return self.child.event(ev, x, y, st)

        def shake(self):
            """每次的轻微移动,自带偏差"""
            d1=self.d_default
            d2=self.d_mouse
            while(self.shaking):
                # 误差颤动
                self.x+=random.randint(-d1,d1)
                self.y+=random.randint(-d1,d1)

                # 鼠标控制
                if random.randint(0,1):
                    x,y = renpy.get_mouse_pos()
                    self.x += d2 if(x>self.x) else -d2
                    self.y += d2 if(y>self.y) else -d2

                # 显示与循环
                renpy.redraw(self, 0)
                time.sleep(self.tiny_time)

        def start_shake(self):
            """对外接口之一,让飞镖动起来"""
            # 当前没有开始才能开始,否则可能重复开始造成过多定时器
            if self.shaking == False:
                self.shaking = True
                # 用Timer达到多线程的效果
                self.t = Timer(0, self.shake)
                self.t.start()

        def debug_shoot(self):
            """测试用,飞镖位置完全变为鼠标位置,并计算得分"""
            x,y = renpy.get_mouse_pos()
            self.x = x
            self.y = y

            # 显示与循环
            renpy.redraw(self, 0)
            self.get_score()

        def end_shake(self):
            """对外接口之一,让飞镖停止运动"""
            self.shaking = False
            renpy.redraw(self, 0)

        def get_score(self):
            """对外接口之一,根据飞镖位置计算得分"""
            """注意当计算得分的时候就需要停了"""
            self.end_shake()

            dx = self.x-self.aim_x
            dy = self.aim_y-self.y

            dist = math.sqrt( dx**2 + dy**2 )
            # 中心环
            if dist < 9:
                self.score=100
            # 中心环2
            elif dist < 25:
                self.score=50
            # 脱靶
            elif dist > 180:
                self.score=0
            # 扇形区间
            else:
                k=1
                if 95<=dist<=114:
                    k=3
                if 159<=dist<=180:
                    k=2

                dg = math.atan2(dx,dy)/math.pi*180
                dg += 180
                dg /= 18
                dg += 0.5
                score_list=[3,19,7,16,8,11,14,9,12,5,20,1,18,4,13,6,10,15,2,17,3]
                self.score=score_list[int(dg)]*k

        def reset_dart(self):
            # 最后要把位置放回原点,便于下次开始射
            self.x = self.aim_x
            self.y = self.aim_y

    my_dart = Dart("dart.png",offset=(-43,-44))


暴露出来的接口是:
start_shake:让飞镖开始抖动
end_shake:让飞镖停止抖动
get_score:根据飞镖当前位置计算得分

二、扔飞镖的界面
[RenPy] 纯文本查看 复制代码
screen darts():
    # 飞镖
    default state=0
    imagebutton:
        idle "dart_empty"
        action [my_dart.get_score,SetScreenVariable("state",1)]
    add my_dart
    if state:
        timer 1.0 action Return()

    # 测试用工具栏
    # text "分数:[score]"
    # hbox:
    #     align (0.5,1.0)
    #     spacing 20
    #     textbutton "抖!" action my_dart.start_shake
    #     textbutton "停!" action my_dart.end_shake
    #     textbutton "射!" action [my_dart.get_score,Return()]


基本就是把整个背景作为一个imagebutton,按了以后就my_dart.get_score来算一下分数,然后设置一下界面变量来启动计时,射完飞镖1秒钟后返回结果。
底下有被注释掉的工具栏,主要是用来测试得分精准性和快速模拟多次扔飞镖的。

这个东西仍然是(第四次放送)我给《罗曼圣诞探案集》做的,花了一个中午一个下午半个晚上,扔飞镖都扔得我头晕了。我是因为这个游戏才了解到的RenPy,主创也是我的好朋友。
打个小广告。
《罗曼圣诞探案集》,使用RenPy引擎制作,已上架steam,目前好评率97%,特别好评发售中!

评分

参与人数 1干货 +1 收起 理由
BuErShen + 1 鼓励原创!

查看全部评分

发表于 2020-3-23 13:17:09 | 显示全部楼层
这个小游戏不错,我居然玩了半个小时。
回复 支持 抱歉

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|RenPy中文空间 ( 苏ICP备17067825号|苏公网安备 32092302000068号 )

GMT+8, 2024-12-23 01:34 , Processed in 0.112195 second(s), 28 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表