| 赞 | 12 |
| VIP | |
| 好人卡 | |
| 积分 | 28 |
| 经验 | |
| 最后登录 | 2024-1-27 |
| 在线时间 | 585 小时 |
- 梦石
- 0
- 星屑
- 2821
- 在线时间
- 585 小时
- 注册时间
- 2022-7-13
- 回帖
- 81
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 我为鱼肉 于 2023-8-20 10:26 编辑
原理简单,操作变量,有注释。可自定义任意不规则形状,有落点“影子”功能。
俄罗斯方块.zip
(1.12 MB, 下载次数: 31)
[fold=代码][pre lang="ruby"]module RPG::Cache
def self.tetris(filename, hue = 0)
load_bitmap("Graphics/Tetris/", filename, hue)
end
end
#==============================================================================
# ** Tetris俄罗斯方块游戏
#==============================================================================
class Tetris
#自定义小块的样式/形状/颜色(文件名,使用RPG::Cache.tetris读取)
Element = ["blue", "cyan", "green", "purple", "red", "yellow"]
Element.insert(0, "gray")#影子块
#读取数据
Structure = load_data("Data/Tetris/Structure.rxdata")
Ushape = load_data("Data/Tetris/Ushape.rxdata")
Right = load_data("Data/Tetris/Right.rxdata")
Left = load_data("Data/Tetris/Left.rxdata")
=begin
#以下展示这些数据的生成过程,方便自定义结构(可以是任意的)与快速生成数据。
#自定义方块结构。一个""代表某一行的数据,0空 1实
input = []
input[0] = ["11", "11"]#〇
input[1] = ["1111"]#I
input[2] = ["1", "1", "1", "1"]
input[3] = ["011", "110"]#S
input[4] = ["10", "11", "01"]
input[5] = ["110", "011"]#Z
input[6] = ["01", "11", "10"]
input[7] = ["010", "111"]#T
input[8] = ["10", "11", "10"]
input[9] = ["111", "010"]
input[10] = ["01", "11", "01"]
input[11] = ["10", "10", "11"]#L
input[12] = ["111", "100"]
input[13] = ["11", "01", "01"]
input[14] = ["001", "111"]
input[15] = ["01", "01", "11"]#J
input[16] = ["100", "111"]
input[17] = ["11", "10", "10"]
input[18] = ["111", "001"]
#生成方块结构数据。二位数组 0空 1实
Structure = []
for i in 0...input.size
data = Table.new(input[0].size, input.size)
for y in 0...data.ysize
for x in 0...data.xsize
data[x, y] = input[y][x].chr.to_i
end
end
Structure = data
end
save_data(Structure, "Data/Tetris/Structure.rxdata")
#自定义旋转类型。"Right[1] = 2"表示1号方块顺时针旋转为2号方块,Left逆时针同理
Right = []
Right[1] = 2 ; Right[2] = 1
Right[3] = 4 ; Right[4] = 3
Right[5] = 6 ; Right[6] = 5
Right[7] = 8 ; Right[8] = 9 ; Right[9] = 10 ; Right[10] = 7
Right[11] = 12 ; Right[12] = 13 ; Right[13] = 14 ; Right[14] = 11
Right[15] = 16 ; Right[16] = 17 ; Right[17] = 18 ; Right[18] = 15
Left = []
Left[1] = 2 ; Left[2] = 1
Left[3] = 4 ; Left[4] = 3
Left[5] = 6 ; Left[6] = 5
Left[7] = 10 ; Left[8] = 7 ; Left[9] = 8 ; Left[10] = 9
Left[15] = 18 ; Left[16] = 15 ; Left[17] = 16 ; Left[18] = 17
save_data(Right, "Data/Tetris/Right.rxdata")
save_data(Left, "Data/Tetris/Left.rxdata")
#生成“U形”数据(从左、右、下方看第一个不为空的坐标,方便做移动判定)
#这里不需要自定义,只需要设置好input/Structure,代码自动生成。
Ushape = []
for i in 0...Structure.size
left = {}
right = {}
down = {}
for y in 0...Structure.ysize
for x in 0...Structure.xsize
if Structure[x, y] > 0 and left[y].nil?
left[y] = [x, y]
end
rx = Structure.xsize - 1 - x
if Structure[rx, y] > 0 and right[y].nil?
right[y] = [rx, y]
end
end
end
for x in 0...Structure.xsize
for y in 0...Structure.ysize
dy = Structure.ysize - 1 - y
if Structure[x, dy] > 0 and down[x].nil?
down[x] = [x, dy]
end
end
end
Ushape = [left.values, right.values, down.values]
end
save_data(Ushape, "Data/Tetris/Ushape.rxdata")
=end
#--------------------------------------------------------------------------
# * initialize初始化
# task 分数目标,>=目标胜利
# level 难度(帧数),数字越大砖块下落越慢
#--------------------------------------------------------------------------
def initialize(task, level)
@drawn = Table.new(10, 20)#生成一个宽度10高度20的画板
@redraw = Table.new(10, 20)
reset_active
@score = 0
@count = 0
@task = task
@level = level
@rect = Rect.new(0, 0, 23, 23)#每个小块23*23与Element对应
@clear = Color.new(0, 0, 0, 0)
end
#--------------------------------------------------------------------------
# * reset_active重设方块
# f 初始化数据??? false初始化 true按照@following继续再随机一个@following
#--------------------------------------------------------------------------
def reset_active(f = false)
@active = f ? @following : Structure[rand(Structure.size)]
@active_element = f ? @following_element : 1 + rand(Element.size - 1)
@x = (10 - @active.xsize) / 2
@y = -@active.ysize
@following = Structure[rand(Structure.size)]
@following_element = 1 + rand(Element.size - 1)
make_highest#生成当前条件下@active最大Y坐标
end
#--------------------------------------------------------------------------
# * redraw_follower重绘预告框
#--------------------------------------------------------------------------
def redraw_follower
@follower.bitmap.fill_rect(0, 0, 230, 124, @clear)#相当于.clear
bitmap = RPG::Cache.tetris(Element[@following_element])
x = (230 - 23 * @following.xsize) / 2#保证始终展示在bitmap中央
y = (124 - 23 * @following.ysize) / 2
for c in 0...@following.xsize
for r in 0...@following.ysize
next if @following[c, r] == 0
@follower.bitmap.blt(x + c * 23, y + r * 23, bitmap, @rect)
end
end
end
#--------------------------------------------------------------------------
# * redraw_degree重绘难度牌 分数越高难度越高???
#--------------------------------------------------------------------------
def redraw_degree
@degree.bitmap.fill_rect(0, 0, 198, 22, @clear)
@degree.bitmap.draw_text(0, 0, 198, 22, @level.to_s, 2)
end
#--------------------------------------------------------------------------
# * redraw_scorer重绘计分器
#--------------------------------------------------------------------------
def redraw_scorer
@scorer.bitmap.fill_rect(0, 0, 198, 22, @clear)
@scorer.bitmap.draw_text(0, 0, 198, 22, @score.to_s, 2)
end
#--------------------------------------------------------------------------
# * adder叠加器(@drawn和@active的叠加),用以判断(x, y)是否需要重绘
#--------------------------------------------------------------------------
def adder(x, y)
if @drawn[x, y] > 0
return @drawn[x, y]
end
if x >= @x and
x <= @x + @active.xsize - 1 and
y >= @y and
y <= @y + @active.ysize - 1
if @active[x - @x, y - @y] > 0
return @active_element
end
else
if @shadow and x >= @x and
x <= @x + @active.xsize - 1 and
y >= @highest and
y <= @highest + @active.ysize - 1
return 99 if @active[x - @x, y - @highest] > 0#影子
end
end
return 0
end
#--------------------------------------------------------------------------
# * redraw_board自重绘 这个方法或许有些多余了,只需改变@drawn时直接重绘即可
#--------------------------------------------------------------------------
def redraw_board
for x in 0..9
for y in 0..19
value = adder(x, y)
if @redraw[x, y] != value
@redraw[x, y] = value
if @redraw[x, y] == 0
@board.bitmap.fill_rect(23 * x, 23 * y, 23, 23, @clear)
elsif @redraw[x, y] == 99#影子
bitmap = RPG::Cache.tetris(Element[0])
@board.bitmap.blt(x * 23, y * 23, bitmap, @rect)
else
bitmap = RPG::Cache.tetris(Element[@redraw[x, y]])
@board.bitmap.blt(x * 23, y * 23, bitmap, @rect)
end
end
end
end
end
#--------------------------------------------------------------------------
# * earn得分lines消除了几行
#得分=行数*(30+(100-难度)/10)
#--------------------------------------------------------------------------
def earn(lines)
@score += lines * (30 + (100 - @level) / 10)
end
#--------------------------------------------------------------------------
# * victory游戏胜利
#--------------------------------------------------------------------------
def victory
print "胜利!"
$scene = Scene_Map.new
end
#--------------------------------------------------------------------------
# * defeat游戏失败
#--------------------------------------------------------------------------
def defeat
print "失败!"
$scene = Scene_Map.new
end
#--------------------------------------------------------------------------
# * 消除判断
#--------------------------------------------------------------------------
def judge
#取得最小y和消除了多少行
min = -1
lines = 0
for y in @y..19
drawn = 100
for x in 0..9
drawn = @drawn[x, y] if @drawn[x, y] < drawn
end
if drawn > 0
min = y if min == -1
lines += 1
end
end
#交换数据
for r in 0..min - 1
y = min - 1 - r
for c in 0..9
@drawn[c, y + lines] = @drawn[c, y]
end
end
#其他处理
earn(lines)
redraw_scorer
if @score >= @task
victory
end
end
#--------------------------------------------------------------------------
# * 移动碰撞检测
# direction方向 0左 1右 2下
# step步数 仅在make_highest中使用
#--------------------------------------------------------------------------
def move_collision(direction, step = 1)
u = Ushape[Structure.index(@active)][direction]
add_x = add_y = 0
case direction
when 0
add_x = -1
when 1
add_x = 1
when 2
add_y = step
end
for i in u
x = @x + i[0] + add_x
y = @y + i[1] + add_y
next if y < 0
if y > 19 or @drawn[x, y] > 0
return true
end
end
return false
end
#--------------------------------------------------------------------------
# * move_left左移动
#--------------------------------------------------------------------------
def move_left
return if @x == 0 or move_collision(0)
@x -= 1
make_highest
end
#--------------------------------------------------------------------------
# * move_right右移动
#--------------------------------------------------------------------------
def move_right
return if @x > 9 - @active.xsize or move_collision(1)
@x += 1
make_highest
end
#--------------------------------------------------------------------------
# * make_highest生成当前状态下@active最大Y坐标
#--------------------------------------------------------------------------
def make_highest
for s in 1..22
if move_collision(2, s)
@highest = @y + s - 1
return
end
end
end
#--------------------------------------------------------------------------
# * move_down下移动
#--------------------------------------------------------------------------
def move_down
if @y == @highest
#碰撞的情况下@y坐标小于0,游戏失败
if @y < 0
defeat
return
end
#把@active数据保存到@drawn
for c in 0...@active.xsize
for r in 0...@active.ysize
if @active[c, r] > 0
@drawn[@x + c, @y + r] = @active_element
end
end
end
#消除判断
judge
#重置当前方块与预告方块
reset_active(true)
redraw_follower
@count = 0
return
end
@y += 1
end
#--------------------------------------------------------------------------
# * fall自下落
#--------------------------------------------------------------------------
def fall
@count += 1
if @count == @level
move_down#向下移动
@count = 0
end
end
#--------------------------------------------------------------------------
# * 旋转,direction0顺时针1逆时针
#--------------------------------------------------------------------------
def rotate(direction)
index = direction == 0 ? Right[Structure.index(@active)] : Left[Structure.index(@active)]
return if index.nil?
#旋转后调整X,Y坐标???
new_x = @x
new_y = @y
#坐标校正
if new_x < 0
new_x = 0
end
if new_x > 10 - @active.xsize
new_x = 10 - @active.xsize
end
if new_y > 20 - @active.ysize
new_y = 20 - @active.ysize
end
#碰撞检测
for c in 0...Structure[index].xsize
for r in 0...Structure[index].ysize
x = new_x + c
y = new_y + r
next if y < 0
if x < 0 or x > 9 or y > 19 or @drawn[x, y] > 0
return
end
end
end
#执行旋转
@x = new_x
@y = new_y
@active = Structure[index]
make_highest
end
#--------------------------------------------------------------------------
# * keyboard按键操作
#--------------------------------------------------------------------------
def keyboard
if Input.repeat?(Input::LEFT)
$game_system.se_play($data_system.cursor_se)
move_left
end
if Input.repeat?(Input::RIGHT)
$game_system.se_play($data_system.cursor_se)
move_right
end
if Input.repeat?(Input::DOWN)
$game_system.se_play($data_system.cursor_se)
move_down
@count = 0
end
if Input.repeat?(Input::UP)
$game_system.se_play($data_system.decision_se)
if @clockwise
rotate(0)
else
rotate(1)
end
end
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
@commands.index = 0
@commands.active = true
@commands.visible = true
return
end
end
#--------------------------------------------------------------------------
# * main场景主处理
#--------------------------------------------------------------------------
def main
#背景
@background = Sprite.new
@background.bitmap = RPG::Cache.tetris("background")
#主内容
@board = Sprite.new
@board.x = 60
@board.y = 10
@board.bitmap = Bitmap.new(230, 460)
#下一个方块预告框
@follower = Sprite.new
@follower.x = 350
@follower.y = 51
@follower.bitmap = Bitmap.new(230, 124)
redraw_follower
#难度框
@degree = Sprite.new
@degree.x = 369
@degree.y = 245
@degree.bitmap = Bitmap.new(198, 22)
redraw_degree
#计分框
@scorer = Sprite.new
@scorer.x = 369
@scorer.y = 337
@scorer.bitmap = Bitmap.new(198, 22)
redraw_scorer
#其他的拓展内容
#菜单
@commands = Window_TetrisCommand.new(160, ["继续", "重开", "影子", "顺时针", "返回"])
@shadow = true#可套到Game_Temp中使用
@clockwise = true
@commands.opacity = 200
@commands.x = (640 - @commands.width) / 2
@commands.y = (480 - @commands.height) / 2
@commands.index = -1
@commands.active = false
@commands.visible = false
Graphics.transition(8, "Graphics/Transitions/020-Flat01")
while $scene == self
Graphics.update
Input.update
update
end
Graphics.freeze
@background.bitmap.dispose
@background.dispose
@board.bitmap.dispose
@board.dispose
@follower.bitmap.dispose
@follower.dispose
@degree.bitmap.dispose
@degree.dispose
@scorer.bitmap.dispose
@scorer.dispose
@commands.dispose
end
#--------------------------------------------------------------------------
# * update场景主刷新
#--------------------------------------------------------------------------
def update
if @commands.active
update_command
return
end
fall
keyboard
redraw_board
end
#--------------------------------------------------------------------------
# * update_command刷新菜单
#--------------------------------------------------------------------------
def update_command
@commands.update
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
@commands.index = -1
@commands.active = false
@commands.visible = false
return
end
if Input.trigger?(Input::C)
$game_system.se_play($data_system.decision_se)
case @commands.index
when 0
@commands.index = -1
@commands.active = false
@commands.visible = false
when 1
for x in 0..9
for y in 0..19
@drawn[x, y] = 0
end
end
reset_active
@score = 0
@count = 0
redraw_board
redraw_follower
redraw_scorer
@commands.index = -1
@commands.active = false
@commands.visible = false
when 2
if @shadow
@commands.disable_item(2)
@shadow = false
else
@commands.draw_item(2)
@shadow = true
end
when 3
if @clockwise
@commands.replace_commands(3, "逆时针")
@clockwise = false
@commands.disable_item(2) unless @shadow
else
@commands.replace_commands(3, "顺时针")
@clockwise = true
@commands.disable_item(2) unless @shadow
end
when 4
$scene = Scene_Map.new
end
end
end
end
class Window_TetrisCommand < Window_Command
def replace_commands(index, command)
@commands[index] = command
draw_item(index)
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
for i in 0...@item_max
draw_item(i)
end
end
#--------------------------------------------------------------------------
# * Draw Item
# index : item number
# color : text color
#--------------------------------------------------------------------------
def draw_item(index, color = normal_color)
self.contents.font.color = color
rect = Rect.new(4, 32 * index, self.contents.width - 8, 32)
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
self.contents.draw_text(rect, @commands[index], 1)
end
end[/pre][/fold]
|
|