Project1
标题:
支援RMXP的Tilemap
[打印本页]
作者:
david50407
时间:
2009-7-5 14:33
标题:
支援RMXP的Tilemap
本帖最后由 david50407 于 2009-7-5 14:55 编辑
終於將RMXP的Tilemap研究出來了
跟原版的差不多
但在使用flash_data的部份有點卡
希望能討論下
畢竟RUBY不能贏VC
以下是腳本
class Tilemap
WIN_W = 640
WIN_H = 480
AREA_W = 32
AREA_H = 32
AREA_X = WIN_W / AREA_W
AREA_Y = WIN_H / AREA_H
ANI_T = 20 #動畫等待時間(單位:畫格)
FLA_T = 4 #閃爍等待時間(單位:畫格)
FLA_O=[110,100,90,80,70,80,90,100] #畫面閃爍變化
#畫自動元件用
AUTO_XY = [
[8, 8, 8, 8], [3, 8, 8, 8], [8, 3, 8, 8], [3, 3, 8, 8],
[8, 8, 8, 3], [3, 8, 8, 3], [8, 3, 8, 3], [3, 3, 8, 3],
[8, 8, 3, 8], [3, 8, 3, 8], [8, 3, 3, 8], [3, 3, 3, 8],
[8, 8, 3, 3], [3, 8, 3, 3], [8, 8, 3, 3], [3, 3, 3, 3],
[7, 7, 7, 7], [7, 3, 7, 7], [7, 7, 7, 3], [7, 3, 7, 3],
[5, 5, 5, 5], [5, 5, 5, 3], [5, 5, 3, 5], [5, 5, 3, 3],
[9, 9, 9, 9], [9, 9, 3, 9], [3, 9, 9, 9], [3, 9, 3, 9],
[11, 11, 11, 11], [3, 11, 11, 11], [11, 3, 11, 11], [3, 3, 11, 11],
[7, 9, 7, 9], [5, 5, 11, 11], [4, 4, 4, 4], [4, 4, 4, 3],
[6, 6, 6, 6], [6, 6, 3, 6], [12, 12, 12, 12], [3, 12, 12, 12],
[10, 10, 10, 10], [10, 3, 10, 10], [4, 6, 4, 6], [4, 4, 10, 10],
[10, 12, 10, 12], [6, 6, 12, 12], [4, 6, 10, 12], [1, 1, 1, 1]
]
#--------------------------------------------------------------------------
# ● 定義外部變數
#--------------------------------------------------------------------------
attr_accessor :autotiles
attr_accessor :tileset
attr_reader :viewport
#--------------------------------------------------------------------------
# ● 初始化物件
# 內部使用以 @@ 開頭
#--------------------------------------------------------------------------
def initialize(viewport = Viewport.new(0,0,WIN_W,WIN_H))
@autotiles = []
@tileset = nil
@map_data = nil
@flash_data = nil
@priorities = nil
@visible = true
@ox = 0
@oy = 0
@viewport = viewport
@@sprite = {} #元件Sprite
@@cache = {} #元件Cache
@@ani_switch = {} #動畫開關
@@count = 0 #當前顯示動畫
@@counting = 0 #動畫等待畫格
@@flash_layer = nil #畫面閃爍用
@@flash_count = 0 #當前閃爍動畫
@@flash_counting = 0 #閃爍等待畫格
@@last_ox = 0
@@last_oy = 0
@@disposed = false
end
#--------------------------------------------------------------------------
# ● 釋放
#--------------------------------------------------------------------------
def dispose
return if @@disposed
for i in @@cache.values
if i.is_a?(Bitmap)
i.dispose
else
for j in i.values
j.dispose
end
end
end
for i in @@sprite.values
i.dispose
end
@@flash_layer.dispose if @@flash_layer != nil
@@flash_layer.bitmap.dispose if @@flash_layer != nil
@@disposed = true
end
def dispose?
return @@disposed
end
#--------------------------------------------------------------------------
# ● 載入地圖資訊
# 載入後繪製地圖
#--------------------------------------------------------------------------
def map_data
return @map_data
end
def map_data=(data)
@map_data = data
return if @map_data.nil?
# 建立地圖元件Cache(方法一) BEGIN
# 地圖較大時不適用
#for x in 0...@map_data.xsize
# for y in 0...@map_data.ysize
# for l in 0..2
# cache_bitmap(@map_data[x, y, l])
# end
# end
#end
# 建立地圖元件Cache(方法一) END
# 建立地圖元件Cache(方法二) BEGIN
# 元件圖較大時不適用
for auto in 0..6
next if @autotiles[auto].nil?
for i in 0...48
cache_bitmap(auto * 48 + i)
end
end
if @tileset != nil
for y in
[email protected]
/ AREA_H
yy = y * 8
for x in 0...8
cache_bitmap(yy + x + 384)
end
end
end
# 建立地圖元件Cache(方法二) END
# 描繪地圖元件 BEGIN
range_x = (@ox + WIN_W) / AREA_W
range_y = (@oy + WIN_H) / AREA_H
range_x = [range_x, WIN_W / AREA_W - 1].min if @map_data.xsize * AREA_W <= WIN_W
range_y = [range_y, WIN_H / AREA_H - 1].min if @map_data.ysize * AREA_H <= WIN_H
for x in (@ox / AREA_W - 1)..range_x
for y in (@oy / AREA_H - 1)..range_y
for l in 0..2
draw(x, y, l)
end
end
end
# 描繪地圖元件 END
end
#--------------------------------------------------------------------------
# ● 載入地圖優先度
# 載入後重整地圖元件Z座標
#--------------------------------------------------------------------------
def priorities
return @priorities
end
def priorities=(value)
@priorities = value
return if @priorities.nil?
for x in ([@ox / AREA_W - 1, 0].max)..((@ox + WIN_W) / AREA_W)
for y in ([@oy / AREA_H - 1, 0].max)..((@oy + WIN_H) / AREA_H)
for l in 0..2
next if @@sprite[[x, y, l]].nil?
id = @map_data[x, y, l]
next if id.nil?
next if id == 0
z = @priorities[id] == 0 ? 0 : 32 * (1 + @@sprite[[x, y, l]].y / AREA_H + @priorities[id])
z = 0 if z < 0
@@sprite[[x, y, l]].z = z
end
end
end
end
#--------------------------------------------------------------------------
# ● 建立地圖元件Cache
#--------------------------------------------------------------------------
def cache_bitmap(id)
if @@cache[id].nil?
if id < 384 #自動元件的情況
bitmapid = id / 48 - 1
@@cache[id] = {}
@@cache[id][0] = get_bitmap_a(id, bitmapid)
if @autotiles[bitmapid].width > AREA_W * 3
anis = @autotiles[bitmapid].width / AREA_W / 3
for i in 1...anis
@@cache[id][i] = get_bitmap_a(id, bitmapid, i)
end
end
else #一般元件的情況
@@cache[id] = get_bitmap(id)
end
end
return @@cache[id][0] if @@cache[id].is_a?(Hash)
return @@cache[id]
end
#--------------------------------------------------------------------------
# ● 取得地圖元件Bitmap
# get_bitmap : 取得一般地圖元件Bitmap
# get_bitmap_a : 取得自動地圖元件Bitmap
#--------------------------------------------------------------------------
def get_bitmap(id)
bitmap = Bitmap.new(AREA_W, AREA_H)
rect = Rect.new((id - 384) % 8 * AREA_W, (id - 384) / 8 * AREA_H, AREA_W, AREA_H)
bitmap.blt(0, 0, @tileset, rect)
return bitmap
end
def get_bitmap_a(id, bitmapid, ani = 0)
bitmap = Bitmap.new(AREA_W, AREA_H)
pic_id = id % 48
for i in 0..3
rect_x = (AUTO_XY[pic_id][i] - 1) % 3
rect_y = (AUTO_XY[pic_id][i] - 1) / 3
rect_x *= AREA_W
rect_y *= AREA_H
x = i % 2
y = i / 2
x *= AREA_W / 2
y *= AREA_H / 2
rect = Rect.new(rect_x + x + (ani * AREA_W * 3), rect_y + y, AREA_W / 2, AREA_H / 2)
bitmap.blt(x, y, @autotiles[bitmapid], rect)
end
return bitmap
end
#--------------------------------------------------------------------------
# ● 繪製地圖元件
#--------------------------------------------------------------------------
def draw(x, y, l)
x0 = x
y0 = y
# 數值修正
x -= @map_data.xsize if x >= @map_data.xsize
x += @map_data.xsize if x < 0
y -= @map_data.ysize if y >= @map_data.ysize
y += @map_data.ysize if y < 0
id = @map_data[x, y, l]
return if id == 0
unless @@sprite[[x, y, l]].nil?
@@sprite[[x, y, l]].x = x0 * AREA_W - @ox
@@sprite[[x, y, l]].y = y0 * AREA_H - @oy
return if @priorities.nil?
z = @priorities[id] == 0 ? 0 : 32 * (1 + @@sprite[[x, y, l]].y / AREA_H + @priorities[id])
z = 0 if z < 0
@@sprite[[x, y, l]].z = z
return
end
@@sprite[[x, y, l]] = Sprite.new(@viewport)
@@sprite[[x, y, l]].x = x0 * AREA_W - @ox
@@sprite[[x, y, l]].y = y0 * AREA_H - @oy
@@sprite[[x, y, l]].z = l
@@sprite[[x, y, l]].bitmap = cache_bitmap(id)
if id < 384
if @@cache[id].length > 1
#動畫
@@ani_switch[[x, y, l]] = true
@@sprite[[x, y, l]].bitmap = @@cache[id][@@count % @@cache[id].length]
end
end
return if @priorities.nil?
z = @priorities[id] == 0 ? 0 : 32 * (1 + @@sprite[[x, y, l]].y / AREA_H + @priorities[id])
z = 0 if z < 0
@@sprite[[x, y, l]].z = z
end
#--------------------------------------------------------------------------
# ● 繪製地圖元件閃爍
#--------------------------------------------------------------------------
def draw_flash
return if @flash_data.nil?
return if @flash_data.xsize <= -1 && @flash_data..ysize <= -1
if @@flash_layer.nil?
@@flash_layer = Plane.new(@viewport)
@@flash_layer.blend_type = 1
@@flash_layer.bitmap = Bitmap.new(@flash_data.xsize * AREA_W, @flash_data.ysize * AREA_H) if @@flash_layer.bitmap.nil?
end
@@flash_layer.z = 1
tmpcolor = Color.new(0,0,0,0)
for x in 0...@flash_data.xsize
for y in 0...@flash_data.ysize
rgb = {}
%w(r g b).inject(@flash_data[x, y]) {|a,b| rest, rgb[b] = a.divmod(16); rest}
next if rgb == {'r'=>0,'g'=>0,'b'=>0}
tmpcolor.set(rgb['r']*16,rgb['g']*16,rgb['b']*16)
@@flash_layer.bitmap.fill_rect(x*AREA_W,y*AREA_H,AREA_W,AREA_H,tmpcolor)
end
end
@@flash_layer.opacity=FLA_O[@@flash_count]
end
#--------------------------------------------------------------------------
# ● 設定地圖座標
#--------------------------------------------------------------------------
def ox
return @ox
end
def oy
return @oy
end
def ox=(ox)
return if @ox == ox
@@last_ox = @ox if @@last_ox == @ox
@ox = ox
@@flash_layer.ox = ox % WIN_W if @@flash_layer != nil
return @ox
end
def oy=(oy)
return if @oy == oy
@@last_oy = @oy if @@last_oy == @oy
@oy = oy
@@flash_layer.oy = oy % WIN_H if @@flash_layer != nil
return @oy
end
#--------------------------------------------------------------------------
# ● 設定地圖顯示
#--------------------------------------------------------------------------
def visible
return @visible
end
def visible=(value)
@visible = value
for i in @@sprite.values
i.visible = @visible
end
@@flash_layer.visible = @visible
return @visible
end
#--------------------------------------------------------------------------
# ● 更新地圖元件閃爍
#--------------------------------------------------------------------------
def flash_data
return @flash_data
end
def flash_data=(data)
return @flash_data if @flash_data == data
@flash_data = data
draw_flash
return @flash_data
end
#--------------------------------------------------------------------------
# ● 更新地圖元件
#--------------------------------------------------------------------------
def update
# 更新動畫等待畫格
if @@counting >= ANI_T
@@counting = 0
@@count += 1
for i in @@ani_switch.keys
id = @map_data[i[0], i[1], i[2]]
@@sprite[i].bitmap = @@cache[id][@@count % @@cache[id].length]
end
else
@@counting += 1
end
# 更新閃爍等待畫格
@@flash_counting += 1
if @@flash_counting >= FLA_T
@@flash_counting = 0
@@flash_count = (@@flash_count + 1) % FLA_O.size
@@flash_layer.opacity=FLA_O[@@flash_count] if @@flash_layer != nil
end
if @ox != @@last_ox
#人物走路時候
if @ox % (AREA_W / 2) != 0
for i in @@sprite.values
i.ox = @ox - @@last_ox
end
else
refreshox
@@last_ox = @ox
end
end
if @oy != @@last_oy
#人物走路時候
if @oy % AREA_H != 0
for i in @@sprite.values
i.oy = @oy - @@last_oy
end
else
refreshoy
@@last_oy = @oy
end
end
for i in @@sprite.keys
id = @map_data[i[0],i[1],i[2]]
if @priorities[id] != 0
@@sprite[i].z = @priorities[id] == 0 ? 0 : 32 * (1 + @@sprite[i].y / AREA_H + @priorities[id])
@@sprite[i].update
end
end
end
#--------------------------------------------------------------------------
def refreshox
#需要釋放的元件範圍
del_range_y = [(@@last_oy / AREA_H - 1), ((@@last_oy + WIN_H) / AREA_H)]
if @ox > @@last_ox
del_range_x = [(@@last_ox / AREA_W - 1), (@ox / AREA_W - 2)]
else
del_range_x = [((@ox + WIN_W) / AREA_W + 1), ((@@last_ox + WIN_W) / AREA_W)]
end
#需要繪製的元件範圍
draw_range_y = [(@oy / AREA_H - 1), ((@oy + WIN_H) / AREA_H)]
if @ox > @@last_ox
draw_range_x = [[((@@last_ox + WIN_W) / AREA_W + 1), (@ox / AREA_W - 1)].max, ((@ox + WIN_W) / AREA_W)]
else
draw_range_x = [(@ox / AREA_W - 1), ([(@@last_ox / AREA_W - 1),(@ox + WIN_W) / AREA_W + 1].min - 1)]
end
#釋放元件 BEGIN
for x in del_range_x[0]..del_range_x[1]
next if draw_range_x[0] > x && x < draw_range_x[1]
for y in del_range_y[0]..del_range_y[1]
next if draw_range_y[0] > y && y < draw_range_y[1]
for l in 0..2
next if @@sprite[[x, y, l]].nil?
@@sprite[[x, y, l]].dispose
@@sprite.delete([x, y, l])
@@ani_switch.delete([x, y, l])
end
end
end
#釋放元件 END
#恢復走路時候的偏移 BEGIN
if @ox >= (@map_data.xsize * AREA_W - WIN_W)
for i in @@sprite.keys
@@sprite[i].ox = 0
@@sprite[i].x = i[0] * AREA_W - @ox
if i[0] < (@ox / 32 - 1)
@@sprite[i].x += @map_data.xsize * AREA_W
elsif i[0] == -1
@@sprite[i].x = 0
end
end
else
for i in @@sprite.keys
@@sprite[i].ox = 0
@@sprite[i].x = i[0] * AREA_W - @ox
end
end
#恢復走路時候的偏移 END
#繪製元件 BEGIN
for x in draw_range_x[0]..draw_range_x[1]
for y in draw_range_y[0]..draw_range_y[1]
for l in 0..2
draw(x, y, l)
end
end
end
#繪製元件 END
end
#--------------------------------------------------------------------------
def refreshoy
#需要釋放的元件範圍
del_range_x = [(@@last_ox / AREA_W - 1), ((@@last_ox + WIN_W) / AREA_W)]
if @oy > @@last_oy
del_range_y = [(@@last_oy / AREA_H - 1), (@oy / AREA_H - 2)]
else
del_range_y = [((@oy + WIN_H) / AREA_H + 1), ((@@last_oy + WIN_H) / AREA_H)]
end
#需要繪製的元件範圍
draw_range_x = [(@ox / AREA_W - 1), ((@ox + WIN_W) / AREA_W)]
if @oy > @@last_oy
draw_range_y = [[((@@last_oy + WIN_H) / AREA_H + 1), (@oy / AREA_H - 1)].max, ((@oy + WIN_H) / AREA_H)]
else
draw_range_y = [(@oy / AREA_H - 1), ([(@@last_oy / AREA_H - 1),(@oy + WIN_H) / AREA_H + 1].min - 1)]
end
#釋放元件 BEGIN
for x in del_range_x[0]..del_range_x[1]
next if draw_range_x[0] > x && x < draw_range_x[1]
for y in del_range_y[0]..del_range_y[1]
next if draw_range_y[0] > y && y < draw_range_y[1]
for l in 0..2
next if @@sprite[[x, y, l]].nil?
@@sprite[[x, y, l]].dispose
@@sprite.delete([x, y, l])
@@ani_switch.delete([x, y, l])
end
end
end
#釋放元件 END
#恢復走路時候的偏移 BEGIN
if @oy >= (@map_data.ysize * AREA_H - WIN_H)
for i in @@sprite.keys
@@sprite[i].oy = 0
@@sprite[i].y = i[1] * AREA_H - @oy
if i[1] < (@oy / 32 - 1)
@@sprite[i].y += @map_data.ysize * AREA_H
elsif i[1] == -1
@@sprite[i].y = 0
end
end
else
for i in @@sprite.keys
@@sprite[i].oy = 0
@@sprite[i].y = i[1] * AREA_H - @oy
end
end
#恢復走路時候的偏移 END
#繪製元件 BEGIN
for x in draw_range_x[0]..draw_range_x[1]
for y in draw_range_y[0]..draw_range_y[1]
for l in 0..2
draw(x, y, l)
end
end
end
#繪製元件 END
end
end
复制代码
ps:
640*480 fps 在38左右
800*600 fps 在35左右
作者:
orochi2k
时间:
2009-7-6 08:43
呃……在我那个之外又多了什么东西么 囧
作者:
DeathKing
时间:
2009-7-6 08:48
畢竟RUBY不能贏VC
Ruby的速率比VB都都还慢,别说C了……
作者:
david50407
时间:
2009-7-13 16:11
@shadow = Bitmap.new(SIZEX, SIZEY)
@shadow.fill_rect(0, 0, 17, SIZEY, Color.new(0, 0, 0, 120))#陰影
事實上RMXP不需要繪製陰影
@passages是VX的屬性,XP亦無
@backbitmap[id + 10000] 也有問題,
因為XP的地圖元件數不限大小,一旦元件數超過10000就完了
作者:
云之殇
时间:
2009-10-20 00:36
老实说,这个脚本不是非一般的卡,一出来半边黑,基本上作用是学院派的
作者:
霎那爱
时间:
2009-10-20 15:39
提示:
作者被禁止或删除 内容自动屏蔽
作者:
tjpaq
时间:
2009-10-28 13:11
提示:
作者被禁止或删除 内容自动屏蔽
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1