Nyaatrap

アダルトロリ百合ゲー開発ブログ。一部記事は18歳未満閲覧禁止です。

Home 商用ゲーム フリーゲーム

Ren'py 用 3Dダンジョンフレームワーク

次次作のために、 Ren'py で3Dダンジョンを徘徊する簡単なプログラムを作りました。

Clipboard 1

1,0の配列で作られたマップの中を自由に徘徊できるうえ、エンカウントバトルもします。
サンプルゲームをアップロードしましたので、自由に改良して使ってください。
扱いはパブリックドメインと同様とします。
ダウンロード: http://www.mediafire.com/?r9kw1nttg5m231m
以下、コードの全てを記しておきます。


init python:
# Create skills (name, hit, power)
Slash = Skill("Slash", 70, 20)

# Create battle actors (name, max_hp, skills)
player = Actor("Hero",100, [Slash])
Goblin = Actor("Goblin",40,[Slash])

# Create maps
stage1=[
"1111111111",
"1111011001",
"1000000001",
"1110111101",
"1000000001",
"1111111111",
[Goblin] # Propeties outside of a map can be use in events. This is an encounter batttle event.
]

label start:
# Create a player position (map,y,x,dy,dx).
# dx,dy means direction. If dy=1, it's down. If dx=-1, it's left.
$ here=Position(stage1,2,2,0,1)
jump dungeon

label dungeon:
$ event_check=False
$ config.rollback_enabled=False
while 1:
python:
# Calculate relative coordinate
turnback=Position(here.map,here.y,here.x,-here.dy,-here.dx)
turnright=Position(here.map,here.y,here.x,here.dx,-here.dy)
turnleft=Position(here.map,here.y, here.x,-here.dx,here.dy)
right1=Position(here.map,here.y+here.dx,here.x-here.dy,here.dy,here.dx)
left1=Position(here.map,here.y-here.dx,here.x+here.dy,here.dy,here.dx)
front1=Position(here.map,here.y+here.dy,here.x+here.dx, here.dy,here.dx)
right2=Position(front1.map,front1.y+front1.dx,front1.x-front1.dy,front1.dy,front1.dx)
left2=Position(front1.map,front1.y-front1.dx,front1.x+front1.dy,front1.dy,front1.dx)
front2=Position(front1.map,front1.y+front1.dy,front1.x+front1.dx, front1.dy,front1.dx)
right3=Position(front2.map,front2.y+front2.dx,front2.x-front2.dy,front2.dy,front2.dx)
left3=Position(front2.map,front2.y-front2.dx,front2.x+front2.dy,front2.dy,front2.dx)

# Composite background images. Try-except clauses are used to prevent the List Out of Index Error
renpy.scene()
renpy.show("base")
try:
if left3.map[left3.y][left3.x]=="1": renpy.show("left3")
except:
pass
try:
if right3.map[right3.y][right3.x]=="1": renpy.show("right3")
except:
pass
try:
if front2.map[front2.y][front2.x]=="1": renpy.show("front2")
except:
pass
try:
if left2.map[left2.y][left2.x]=="1": renpy.show("left2")
except:
pass
try:
if right2.map[right2.y][right2.x]=="1": renpy.show("right2")
except:
pass
if front1.map[front1.y][front1.x]=="1": renpy.show("front1")
if left1.map[left1.y][left1.x]=="1": renpy.show("left1")
if right1.map[right1.y][right1.x]=="1": renpy.show("right1")

# Check events and jump if happens
if event_check and not here.map[-1] == [] and renpy.random.random()<.2:
renpy.jump("battle")

# Else, call the move screen
event_check = True
here = renpy.call_screen("move")

label battle:
# Copy monster instances not to modify the originals
$ enemy=copy(renpy.random.choice(here.map[-1]))
show screen battle_ui
"[enemy.name] appeared"
while enemy.hp>0:
$ player.command(enemy)
if player.hp <1:
"gameover"
$ renpy.full_restart()
"You win"
hide screen battle_ui
jump dungeon

init -1 python:
# Import the copy module for copying instanses.
from copy import copy

# Class used for relative coodinate
class Position():
def __init__(self,map,y,x,dy,dx):
self.map=map
self.y=y
self.x=x
self.dy=dy
self.dx=dx

# Class used for battle skills
class Skill():
def __init__(self, name, hit, power):
self.name = name
self.hit = hit
self.power = power

# Class used for battle characters. Inherit renpy.store.object for the rollback function.
class Actor(renpy.store.object):
def __init__(self, name, max_hp=0, skills=[]):
self.name=name
self.max_hp=max_hp
self.hp=max_hp
self.skills = skills

def command(self, target):
self.skill = renpy.call_screen("command")
target.skill = renpy.random.choice(target.skills)
self.attack(self.skill, target)
if target.hp < 1:
return
target.attack(target.skill, self)

def attack(self,skill,target):
if self.skill.hit < renpy.random.randint (0,100):
narrator ("{} dodged {}'s attack".format(target.name,self.name))
else:
target.hp -= self.skill.power
narrator ("{} got {} damage".format(target.name, self.skill.power))

init:
# Screen used for moving
screen move:
fixed:
if front1.map[front1.y][front1.x] is not "1":
textbutton "⇧" action Return(value=front1) xcenter .5 ycenter .34
textbutton "⇨" action Return(value=turnright) xcenter .57 ycenter .47
textbutton "⇩" action Return(value=turnback) xcenter .5 ycenter .6
textbutton "⇦" action Return(value=turnleft) xcenter .43 ycenter .47

# Screen used for selecting skills
screen command:
vbox align (.5,.5):
for i in player.skills:
textbutton "[i.name]" action Return (value=i)

# Screen which shows battle status
screen battle_ui:
use battle_frame(char=player, position=(.95,.05))
use battle_frame(char=enemy, position=(.05,.05))

screen battle_frame:
frame area (0, 0, 180, 80) align position:
vbox yfill True:
text "[char.name]"
hbox xfill True:
text "HP"
text "[char.hp]/[char.max_hp]" xalign 1.0

init:
# Assign background images.
image base = "base.png"
image left1 = "left1.png"
image right1 = im.Flip("left1.png", horizontal=True)
image front1 = "front1.png"
image left2 = "left2.png"
image right2 = im.Flip("left2.png", horizontal=True)
image front2 ="front2.png"
image left3 = "left3.png"
image right3 = im.Flip("left3.png", horizontal=True)

# Here is a visualised relative coordinate in this code. Image here=player and facing top.
# left3, front2, right3
# left2, front1, right2
# left1, here , right1

コメント

Ren'Pyについて質問

いつも日本語でRen'Pyを扱っている貴重なブログとして参考にさせてもらっています。
記事の内容とは全然が関係なくてすみませんが、screenのviewportをウィンドウ外から操作する方法を分かりませんか?
具体的にはここのページに関することです、
http://www.renpy.org/wiki/renpy/ja/doc/cookbook/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%81%A8%E9%9F%B3%E5%A3%B0%E3%81%AE%E3%83%AA%E3%83%97%E3%83%AC%E3%82%A4
このままだと履歴ウィンドウ内にマウスがないとホイールを受け付けなくてかなり不便です。
ちょっと自力での解決は難しそうなのですが

  • 2013/02/21(木) 23:09:29 |
  • URL |
  • 赤恐竜 #-
  • [ 編集 ]

試してみましたが、Viewportのサイズをウィンドウ以上にすると表示がおかしくなるみたいですね。それ以外には、
screen:
key "mousedown_4" action YScrollValue(viewport)
くらいしか思いつきません。成功率は低そうですが。

あ、 赤恐竜さんのブログは存じてます。狭い世界ですから ^_^;

  • 2013/02/22(金) 00:01:40 |
  • URL |
  • 瑞毅 #GpEwlVdw
  • [ 編集 ]

ありがとうございます。
しかしその案はすでに試して駄目でした。 org

せっせとカスタマイズ記事かいて宣伝してはいますが、もうちょっと広がってくれないものか。

  • 2013/02/22(金) 01:48:49 |
  • URL |
  • 赤恐竜 #-
  • [ 編集 ]

半日ほど苦闘していたら解決しました。
こんな感じです。
key "rollback" action Uphistory(vp)
key "rollforward" action Downhistory(vp)

class Uphistory(Action):
def __init__(self, view):
self.view = view
def __call__(self):
rv = self.view.yadjustment.change(self.view.yadjustment.value - self.view.yadjustment.step)
if rv is not None:
return rv
else:
raise renpy.display.core.IgnoreEvent()

class Downhistory(Action):
def __init__(self, view):
self.view = view
def __call__(self):
rv = self.view.yadjustment.change(self.view.yadjustment.value + self.view.yadjustment.step)
if rv is not None:
return rv
else:
raise renpy.display.core.IgnoreEvent()

  • 2013/02/22(金) 16:23:00 |
  • URL |
  • 赤恐竜 #-
  • [ 編集 ]

綺麗なコードですね。こちらも参考になります。
あと、事後承諾ですが、サイドバーリンクに加えさせてもらいました。構いませんか?

  • 2013/02/22(金) 19:05:56 |
  • URL |
  • 瑞毅 #JUGsyThY
  • [ 編集 ]

もちろんです。
ありがとうございます。

  • 2013/02/22(金) 19:08:01 |
  • URL |
  • 赤恐竜 #-
  • [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する