|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 Reacted 于 2025-3-2 15:25 编辑
前言:
最近水了一下Renpy的群,发现群里在讨论有关Renpy制作RPG的想法。
正好我正在尝试使用Renpy制作Rpg。(目前实现了自由编辑有高低差的地图,卡牌战斗,人物移动)
但是 我写的一些代码还没有经过重构,所以现在不是最佳的状态,现在仅分享一下人物行走。
之前鄙人发过一个帖子,也是关于人物行走的,但是那次是用screen的timer实现的,这次分享改良后的CDD方案,希望能帮到你们。
最后:如果我的游戏有幸能做出来的话,希望大家可以支持一下。
教程:
第一步:需求分析
分析一下我们要实现的功能:人物行走
这个功能无非就是通过按键来改变人物的坐标,同时播放人物的动画。
那么我们来建立一个空的CDD。
cdd.rpy:
[RenPy] 纯文本查看 复制代码 init python early:
class WalkMan(renpy.Displayable):
def __init__(self,**kwards):
super().__init__(**kwards)
def render(self,width,height,st,at):
render = renpy.Render(width,height)
return render
def event(self,ev,x,y,st):
pass
这样就新建了一个空的CDD。接下来我们给它初始化一下。设置一些属性。
[RenPy] 纯文本查看 复制代码 init python early:
from enum import Enum
#用一个枚举来记录玩家的状态
#玩家的状态也就是走路或者不动
#再细分一下就是左站,右站,上站,下站,左走,右走,上走,下走
class Status(Enum):
LEFT_STAND = 0
RIGHT_STAND = 1
UP_STAND = 2
DOWN_STAND = 3
LEFT_WALK = 4
RIGHT_WALK = 5
UP_WALK = 6
DOWN_WALK = 7
class WalkMan(renpy.Displayable):
def __init__(self,**kwards):
super().__init__(**kwards)
#坐标
self.speed = 10 #玩家速度
self.x = 500 #x坐标
self.y = 500 #y坐标
self.img = Solid(color="#ff0000",xysize=(100,100)) #人物的图片,暂时用红色矩形来替代。
self.status = Status.LEFT_STAND #状态,默认向左站
def render(self,width,height,st,at):
render = renpy.Render(width,height)
return render
def event(self,ev,x,y,st):
pass
然后我们就要来通过按键来改变玩家的状态
那么我们来定义一个函数作为玩家控制器。
然后把它放进event里。
玩家控制器需要用到pygame代码,记得在上面import pygame
[RenPy] 纯文本查看 复制代码 def event(self,ev,x,y,st):
self.player_control(ev,x,y,st)
def player_control(self,ev,x,y,st):
#通过按键改变玩家状态
#如果按下按键,就照着对应的方向走
if ev.type == pygame.KEYDOWN:
if ev.key == pygame.K_a:
self.status = Status.LEFT_WALK
elif ev.key == pygame.K_d:
self.status = Status.RIGHT_WALK
elif ev.key == pygame.K_w:
self.status = Status.UP_WALK
elif ev.key == pygame.K_s:
self.status = Status.DOWN_WALK
#如果松开按键,就照着刚刚走的方向站
if ev.type == pygame.KEYUP:
if self.status == Status.LEFT_WALK:
self.status = Status.LEFT_STAND
elif self.status == Status.RIGHT_WALK:
self.status = Status.RIGHT_STAND
elif self.status == Status.UP_WALK:
self.status = Status.UP_STAND
elif self.status == Status.DOWN_WALK:
self.status = Status.DOWN_STAND
光是改变玩家状态还是不够的,我们还要给它加上速度。所以我们再写一个函数,用来给予速度。
那么速度是有方向的,在RPG游戏中,我们只考虑上下左右四个方向。我们把速度看成一个元组
(速度的值,速度的方向)就行了。
也就是说,速率是speed,速度是velocity。
我们修正一下之前的初始化,并引入方向和速度
[RenPy] 纯文本查看 复制代码 class Direction(Enum):
LEFT = 0
RIGHT = 1
UP = 2
DOWN = 3
class WalkMan(renpy.Displayable):
def __init__(self,**kwards):
super().__init__(**kwards)
#坐标
self.speed = 10 #玩家速率
self.velocity = (0,Direction.LEFT) #玩家速度,默认是0,向左
self.x = 500 #x坐标
self.y = 500 #y坐标
self.pos = self.x,self.y
self.img = Solid(color="#ff0000",xysize=(100,100)) #人物的图片,暂时用红色矩形来替代。
self.status = Status.LEFT_STAND #状态,默认向左走
self.moving = False #判断玩家是否正在移动的标识符,那么开始时肯定不在移动。
然后创建给玩家速度的函数
[RenPy] 纯文本查看 复制代码 def change_player_velocity(self):
speed = self.speed
#如果在走的话,施加速度
if self.status == Status.LEFT_WALK:
self.velocity = (speed,Direction.LEFT)
elif self.status == Status.RIGHT_WALK:
self.velocity = (speed,Direction.RIGHT)
elif self.status == Status.UP_WALK:
self.velocity = (speed,Direction.UP)
elif self.status == Status.DOWN_WALK:
self.velocity = (speed,Direction.DOWN)
#如果不在走,速率就是0(速率是0的话方向就没啥关系了)
else:
self.velocity = (0,Direction.LEFT)
现在玩家会被按键改变状态,change_player_velocity函数会根据玩家的状态给玩家速度。
接下来,我们创建一个根据玩家速度来改变玩家坐标的函数。
说一下改变玩家坐标的思路。
首先,我们肯定希望玩家走路的速度是恒定的。
这里的恒定指的是不会随着游戏的帧率改变而改变。
假设我们直接去拿坐标加的话,x+xspeed,假设这里的速度是10
那么游戏在100帧运行的时候,一秒走的路程是 100xspeed。
游戏在30帧运行的时候,一秒走的路程是30xspeed。
也就是说,玩家实际的速度会变慢很多。
这不是我们想要看到的。
为了防止这样,我们先要获取上一次改变坐标和这一次改变坐标之间的时间--deltatime。
也就是时间的增量
然后 x = x + speed * deltatime
这样玩家走的路程就只与游戏运行时间有关,而不与游戏的帧率有关,也就是玩家的速度不会变。
为了获取时间,我们先在__init__()里加入一个新的属性:self.last_time = 0
那么符合这样要求的函数大概长这样:
[RenPy] 纯文本查看 复制代码 def change_player_pos(self,st):
speed = self.velocity[0]
direction = self.velocity[1]
#获取deltatime
deltatime = st - self.last_time
#更新last_time
self.last_time = st
#如果速度不是0,更新坐标
if speed != 0:
if direction == Direction.LEFT:
self.x += -speed * deltatime
elif direction == Direction.RIGHT:
self.x += speed * deltatime
elif direction == Direction.UP:
self.y += -speed * deltatime
elif direction == Direction.DOWN:
self.y += speed * deltatime
在event中加上所有我们写的函数并更新:
[RenPy] 纯文本查看 复制代码 def event(self,ev,x,y,st):
self.player_control(ev,x,y,st)
self.change_player_velocity()
self.change_player_pos(st)
renpy.restart_interaction()
在render()中将红方块渲染出来。
[RenPy] 纯文本查看 复制代码 def render(self,width,height,st,at):
render = renpy.Render(width,height)
child_render = renpy.render(self.img,width,height,st,at)
render.blit(child_render,(self.x,self.y))
renpy.redraw(self,0)
return render
那么到目前位置控制玩家移动的逻辑就写好了,以下是目前的代码:
[RenPy] 纯文本查看 复制代码 init python early:
from enum import Enum
import pygame
#用一个枚举来记录玩家的状态
#玩家的状态也就是走路或者不动
#再细分一下就是左站,右站,上站,下站,左走,右走,上走,下走
class Status(Enum):
LEFT_STAND = 0
RIGHT_STAND = 1
UP_STAND = 2
DOWN_STAND = 3
LEFT_WALK = 4
RIGHT_WALK = 5
UP_WALK = 6
DOWN_WALK = 7
class Direction(Enum):
LEFT = 0
RIGHT = 1
UP = 2
DOWN = 3
class WalkMan(renpy.Displayable):
def __init__(self,**kwards):
super(WalkMan,self).__init__(**kwards)
#坐标
self.speed = 1000 #玩家速率
self.velocity = (0,Direction.LEFT) #玩家速度,默认是0,向左
self.x = 500 #x坐标
self.y = 500 #y坐标
self.pos = self.x,self.y
self.img = Solid(color="#ff0000",xysize=(100,100)) #人物的图片,暂时用红色矩形来替代。
self.status = Status.LEFT_STAND #状态,默认向左走
self.last_time = 0
def render(self,width,height,st,at):
render = renpy.Render(width,height)
child_render = renpy.render(self.img,width,height,st,at)
render.blit(child_render,(self.x,self.y))
renpy.redraw(self,0)
return render
def event(self,ev,x,y,st):
self.player_control(ev,x,y,st)
self.change_player_velocity()
self.change_player_pos(st)
renpy.restart_interaction()
def player_control(self,ev,x,y,st):
#通过按键改变玩家状态
#如果按下按键,就照着对应的方向走
if ev.type == pygame.KEYDOWN:
if ev.key == pygame.K_a:
self.status = Status.LEFT_WALK
elif ev.key == pygame.K_d:
self.status = Status.RIGHT_WALK
elif ev.key == pygame.K_w:
self.status = Status.UP_WALK
elif ev.key == pygame.K_s:
self.status = Status.DOWN_WALK
#如果松开按键,就照着刚刚走的方向站
if ev.type == pygame.KEYUP:
if self.status == Status.LEFT_WALK:
self.status = Status.LEFT_STAND
elif self.status == Status.RIGHT_WALK:
self.status = Status.RIGHT_STAND
elif self.status == Status.UP_WALK:
self.status = Status.UP_STAND
elif self.status == Status.DOWN_WALK:
self.status = Status.DOWN_STAND
def change_player_velocity(self):
speed = self.speed
#如果在走的话,施加速度
if self.status == Status.LEFT_WALK:
self.velocity = (speed,Direction.LEFT)
elif self.status == Status.RIGHT_WALK:
self.velocity = (speed,Direction.RIGHT)
elif self.status == Status.UP_WALK:
self.velocity = (speed,Direction.UP)
elif self.status == Status.DOWN_WALK:
self.velocity = (speed,Direction.DOWN)
#如果不在走,速率就是0(速率是0的话方向就没啥关系了)
else:
self.velocity = (0,Direction.LEFT)
def change_player_pos(self,st):
speed = self.velocity[0]
direction = self.velocity[1]
#获取deltatime
deltatime = st - self.last_time
#更新last_time
self.last_time = st
#如果速度不是0,更新坐标
if speed != 0:
if direction == Direction.LEFT:
self.x += -speed * deltatime
elif direction == Direction.RIGHT:
self.x += speed * deltatime
elif direction == Direction.UP:
self.y += -speed * deltatime
elif direction == Direction.DOWN:
self.y += speed * deltatime
我们建一个场景来测试一下
script.rpy:
[RenPy] 纯文本查看 复制代码 default wm = WalkMan()
label start:
jump test
return
label test:
call screen test
screen test:
add wm
运行游戏,发现红方块。按wasd可以移动它
接下来我们来渲染走路的贴图。
这里是我的文件,我比较懒,就只做两个方向了,其实做四个方向也是一样的。
建立新的img属性
[RenPy] 纯文本查看 复制代码 self.left_img = ["stand_left.png","walk_left_1.png","walk_left_2.png"]
self.right_img = ["stand_right.png","walk_right_1.png","walk_right_2.png"]
self.img = self.left_img[0]
加一个走路时间的属性
[RenPy] 纯文本查看 复制代码 self.walk_time = 0
这里我们假设0.3秒切换一次图片好了。
那么三张图也就是三个阶段
0秒-0.3秒
0.3-0.6秒
0.6-0.9秒。
写一个更新走路时间的函数。
[RenPy] 纯文本查看 复制代码 def update_walk_time(self,deltatime):
speed = self.velocity[0]
#如果走路时间大于0.9秒就归零
if self.walk_time > 0.9:
self.walk_time = 0
self.walk_time += deltatime
刚刚我们的change_player_pos函数里有deltatime,我们把这个函数放在里面一起跑一下(这样是不好的)
[RenPy] 纯文本查看 复制代码 def change_player_pos(self,st):
speed = self.velocity[0]
direction = self.velocity[1]
#获取deltatime
deltatime = st - self.last_time
#更新last_time
self.last_time = st
self.update_walk_time(deltatime)
#如果速度不是0,更新坐标
if speed != 0:
if direction == Direction.LEFT:
self.x += -speed * deltatime
elif direction == Direction.RIGHT:
self.x += speed * deltatime
elif direction == Direction.UP:
self.y += -speed * deltatime
elif direction == Direction.DOWN:
self.y += speed * deltatime
然后我们来写选择图片的方法。(写的有点乱,见谅)
[RenPy] 纯文本查看 复制代码 def update_walk_img(self):
if self.status == Status.LEFT_STAND:
self.img = self.left_img[0]
elif self.status == Status.RIGHT_STAND:
self.img = self.right_img[0]
elif self.status == Status.RIGHT_WALK:
if self.walk_time<0.3:
self.img = self.right_img[0]
elif 0.3<self.walk_time<=0.6:
self.img = self.right_img[1]
elif 0.6<self.walk_time<=0.9:
self.img = self.right_img[2]
elif self.status == Status.LEFT_WALK:
if self.walk_time<0.3:
self.img = self.left_img[0]
elif 0.3<self.walk_time<=0.6:
self.img = self.left_img[1]
elif 0.6<self.walk_time<=0.9:
self.img = self.left_img[2]
加入到event
[RenPy] 纯文本查看 复制代码 def event(self,ev,x,y,st):
self.player_control(ev,x,y,st)
self.change_player_velocity()
self.change_player_pos(st)
self.update_walk_img()
renpy.restart_interaction()
再次打开游戏测试,发现已经完成了。
附上所有代码
script.rpy:
[RenPy] 纯文本查看 复制代码 default wm = WalkMan()
label start:
jump test
return
label test:
call screen test
screen test:
add wm
cdd.rpy:
[RenPy] 纯文本查看 复制代码 init python early:
from enum import Enum
import pygame
#用一个枚举来记录玩家的状态
#玩家的状态也就是走路或者不动
#再细分一下就是左站,右站,上站,下站,左走,右走,上走,下走
class Status(Enum):
LEFT_STAND = 0
RIGHT_STAND = 1
UP_STAND = 2
DOWN_STAND = 3
LEFT_WALK = 4
RIGHT_WALK = 5
UP_WALK = 6
DOWN_WALK = 7
class Direction(Enum):
LEFT = 0
RIGHT = 1
UP = 2
DOWN = 3
class WalkMan(renpy.Displayable):
def __init__(self,**kwards):
super(WalkMan,self).__init__(**kwards)
#坐标
self.speed = 500 #玩家速率
self.velocity = (0,Direction.LEFT) #玩家速度,默认是0,向左
self.x = 500 #x坐标
self.y = 500 #y坐标
self.pos = self.x,self.y
self.left_img = ["stand_left.png","walk_left_1.png","walk_left_2.png"]
self.right_img = ["stand_right.png","walk_right_1.png","walk_right_2.png"]
self.img = self.left_img[0]
self.status = Status.LEFT_STAND #状态,默认向左走
self.last_time = 0
self.walk_time = 0
def render(self,width,height,st,at):
render = renpy.Render(width,height)
img = Image(self.img)
child_render = renpy.render(img,width,height,st,at)
render.blit(child_render,(self.x,self.y))
renpy.redraw(self,0)
return render
def event(self,ev,x,y,st):
self.player_control(ev,x,y,st)
self.change_player_velocity()
self.change_player_pos(st)
self.update_walk_img()
renpy.restart_interaction()
def player_control(self,ev,x,y,st):
#通过按键改变玩家状态
#如果按下按键,就照着对应的方向走
if ev.type == pygame.KEYDOWN:
if ev.key == pygame.K_a:
self.status = Status.LEFT_WALK
elif ev.key == pygame.K_d:
self.status = Status.RIGHT_WALK
elif ev.key == pygame.K_w:
self.status = Status.UP_WALK
elif ev.key == pygame.K_s:
self.status = Status.DOWN_WALK
#如果松开按键,就照着刚刚走的方向站
if ev.type == pygame.KEYUP:
if self.status == Status.LEFT_WALK:
self.status = Status.LEFT_STAND
elif self.status == Status.RIGHT_WALK:
self.status = Status.RIGHT_STAND
elif self.status == Status.UP_WALK:
self.status = Status.UP_STAND
elif self.status == Status.DOWN_WALK:
self.status = Status.DOWN_STAND
def change_player_velocity(self):
speed = self.speed
#如果在走的话,施加速度
if self.status == Status.LEFT_WALK:
self.velocity = (speed,Direction.LEFT)
elif self.status == Status.RIGHT_WALK:
self.velocity = (speed,Direction.RIGHT)
elif self.status == Status.UP_WALK:
self.velocity = (speed,Direction.UP)
elif self.status == Status.DOWN_WALK:
self.velocity = (speed,Direction.DOWN)
#如果不在走,速率就是0(速率是0的话方向就没啥关系了)
else:
self.velocity = (0,Direction.LEFT)
def change_player_pos(self,st):
speed = self.velocity[0]
direction = self.velocity[1]
#获取deltatime
deltatime = st - self.last_time
#更新last_time
self.last_time = st
self.update_walk_time(deltatime)
#如果速度不是0,更新坐标
if speed != 0:
if direction == Direction.LEFT:
self.x += -speed * deltatime
elif direction == Direction.RIGHT:
self.x += speed * deltatime
elif direction == Direction.UP:
self.y += -speed * deltatime
elif direction == Direction.DOWN:
self.y += speed * deltatime
def update_walk_time(self,deltatime):
speed = self.velocity[0]
#如果走路时间大于0.9秒就归零
if self.walk_time > 0.9:
self.walk_time = 0
self.walk_time += deltatime
def update_walk_img(self):
if self.status == Status.LEFT_STAND:
self.img = self.left_img[0]
elif self.status == Status.RIGHT_STAND:
self.img = self.right_img[0]
elif self.status == Status.RIGHT_WALK:
if self.walk_time<0.3:
self.img = self.right_img[0]
elif 0.3<self.walk_time<=0.6:
self.img = self.right_img[1]
elif 0.6<self.walk_time<=0.9:
self.img = self.right_img[2]
elif self.status == Status.LEFT_WALK:
if self.walk_time<0.3:
self.img = self.left_img[0]
elif 0.3<self.walk_time<=0.6:
self.img = self.left_img[1]
elif 0.6<self.walk_time<=0.9:
self.img = self.left_img[2]
|
|