Project1
标题: 【小游戏】《2048~》RMVA版v0.2 [打印本页]
作者: swebok 时间: 2014-3-26 09:31
标题: 【小游戏】《2048~》RMVA版v0.2 本帖最后由 swebok 于 2014-3-31 21:05 编辑
最近《2048~》这个小游戏挺火的,昨晚思考了一下写了这么个脚本,算法是自己琢磨的。本人RUBY初学者,写的不好请多多包涵,如果出现问题了请@我。
得分和界面功能还没有实现,有时间再填上。
原游戏地址:
http://gabrielecirulli.github.io/2048/
游戏规则:
HOW TO PLAY:Use yourarrow keysto move the tiles. When two tiles with the same number touch, theymerge into one!
NOTE:This site is the official version of 2048. You can play it on your phone via.All other apps or sites are derivatives or fakes, and should be used with caution.
Created by Gabriele Cirulli.Based on 1024 by Veewo Studioand conceptually similar to Threes by Ashe Vollmer.[1]
游戏规则很简单,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块。
工程下载:
http://pan.baidu.com/s/1hqomlt6
2014.3.30更新
参照taroxd的建议修改了工程,具体代码见1L&2L。
#==============================================================================
# □ Scene_Game2048
# 2048小游戏,RMVA版作者:swebok,转载需保留该信息!
# [url]http://rpg.blue/thread-357532-1-1.html[/url]
#==============================================================================
class Scene_Game2048 < Scene_Base
#--------------------------------------------------------------------------
# ● 开始处理
#--------------------------------------------------------------------------
def start
super
init_game
draw_box
end
#--------------------------------------------------------------------------
# ● 结束处理
#--------------------------------------------------------------------------
def terminate
super
@background_sprite .dispose
end
#--------------------------------------------------------------------------
# ● 刷新处理
#--------------------------------------------------------------------------
def update
super
if Input.trigger ?( :LEFT )
@game2048 .move ( :left )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :RIGHT )
@game2048 .move ( :right )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :UP )
@game2048 .move ( :up )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :DOWN )
@game2048 .move ( :down )
judge
clear_box
Sound.play_cursor
draw_box
end
end
#--------------------------------------------------------------------------
# ● 初始化
#--------------------------------------------------------------------------
def init_game
@game2048 = Game2048.new
@background_sprite = Sprite.new
@background_sprite .bitmap = Bitmap.new ( Graphics.width , Graphics.height )
draw_box
end
#--------------------------------------------------------------------------
# ● 擦除格子
#--------------------------------------------------------------------------
def clear_box
@background_sprite .bitmap .clear
end
#--------------------------------------------------------------------------
# ● 描画格子
#--------------------------------------------------------------------------
def draw_box
for i in 0 ...4
for j in 0 ..4
if @game2048 .[ ] ( i, j) != nil
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , @game2048 .[ ] ( i, j) , 1 )
end
end
end
end
#--------------------------------------------------------------------------
# ● 判定结束
#--------------------------------------------------------------------------
def judge
if @game2048 .lose ?
clear_box
draw_box
@background_sprite .bitmap .draw_text ( 120 , 320 , 300 , 24 , "无法移动,你失败了!" , 1 )
$data_system .gameover_me .play
abs_wait( 180 )
SceneManager.goto ( Scene_Map)
end
if @game2048 .win ?
clear_box
draw_box
@background_sprite .bitmap .draw_text ( 120 , 320 , 300 , 24 , "达到2048,恭喜您胜利!" , 1 )
$game_system .battle_end_me .play
abs_wait( 180 )
SceneManager.goto ( Scene_Map)
end
end
#--------------------------------------------------------------------------
# ● 等待(快进无效)
#--------------------------------------------------------------------------
def abs_wait( duration)
duration.times { |i| update_for_wait }
end
#--------------------------------------------------------------------------
# ● 更新画面(等待用)
#--------------------------------------------------------------------------
def update_for_wait
update_basic
end
end
#==============================================================================
# □ Scene_Game2048
# 2048小游戏,RMVA版作者:swebok,转载需保留该信息!
# [url]http://rpg.blue/thread-357532-1-1.html[/url]
#==============================================================================
class Scene_Game2048 < Scene_Base
#--------------------------------------------------------------------------
# ● 开始处理
#--------------------------------------------------------------------------
def start
super
init_game
draw_box
end
#--------------------------------------------------------------------------
# ● 结束处理
#--------------------------------------------------------------------------
def terminate
super
@background_sprite .dispose
end
#--------------------------------------------------------------------------
# ● 刷新处理
#--------------------------------------------------------------------------
def update
super
if Input.trigger ?( :LEFT )
@game2048 .move ( :left )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :RIGHT )
@game2048 .move ( :right )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :UP )
@game2048 .move ( :up )
judge
clear_box
Sound.play_cursor
draw_box
end
if Input.trigger ?( :DOWN )
@game2048 .move ( :down )
judge
clear_box
Sound.play_cursor
draw_box
end
end
#--------------------------------------------------------------------------
# ● 初始化
#--------------------------------------------------------------------------
def init_game
@game2048 = Game2048.new
@background_sprite = Sprite.new
@background_sprite .bitmap = Bitmap.new ( Graphics.width , Graphics.height )
draw_box
end
#--------------------------------------------------------------------------
# ● 擦除格子
#--------------------------------------------------------------------------
def clear_box
@background_sprite .bitmap .clear
end
#--------------------------------------------------------------------------
# ● 描画格子
#--------------------------------------------------------------------------
def draw_box
for i in 0 ...4
for j in 0 ..4
if @game2048 .[ ] ( i, j) != nil
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , @game2048 .[ ] ( i, j) , 1 )
end
end
end
end
#--------------------------------------------------------------------------
# ● 判定结束
#--------------------------------------------------------------------------
def judge
if @game2048 .lose ?
clear_box
draw_box
@background_sprite .bitmap .draw_text ( 120 , 320 , 300 , 24 , "无法移动,你失败了!" , 1 )
$data_system .gameover_me .play
abs_wait( 180 )
SceneManager.goto ( Scene_Map)
end
if @game2048 .win ?
clear_box
draw_box
@background_sprite .bitmap .draw_text ( 120 , 320 , 300 , 24 , "达到2048,恭喜您胜利!" , 1 )
$game_system .battle_end_me .play
abs_wait( 180 )
SceneManager.goto ( Scene_Map)
end
end
#--------------------------------------------------------------------------
# ● 等待(快进无效)
#--------------------------------------------------------------------------
def abs_wait( duration)
duration.times { |i| update_for_wait }
end
#--------------------------------------------------------------------------
# ● 更新画面(等待用)
#--------------------------------------------------------------------------
def update_for_wait
update_basic
end
end
预计更新:
游戏界面;自定义文字、图片信息(比如可以做成2个包子合成一个馒头啦)。
(最近比较忙,预计会龟速更新,但愿别太监就行...)
作者: taroxd 时间: 2014-3-27 08:44
本帖最后由 taroxd 于 2014-3-31 18:45 编辑
写了个纯Ruby类,用来处理2048(然后自己做了个命令行版本),仅供参考。
得分功能只要修改move_left即可。楼主可以看一下move_right等方法是怎么写的
目测 @Max 要被坑
class Game2048
include Enumerable
attr_reader :size
def initialize( size = 4 , max = 2048 )
@size , [ url=home.php ?mod=space&uid=25307 ] @Max[ /url] = size, max
@data = Array .new ( size) { Array .new ( size) }
2 .times { generate }
end
def move( direction)
last = to_a
send :"move_#{direction}"
return if last == to_a
generate
self
end
def [ ] ( i, j)
@data [ i] [ j]
end
def each
return to_enum( __method__) { @size **2 } unless block_given?
@data .each { |row| row.each { |n| yield n } }
end
def each_index
return to_enum( __method__) { @size **2 } unless block_given?
@size .times { |i| @size .times { |j| yield i, j } }
end
def each_with_index
return to_enum( __method__) { @size **2 } unless block_given?
each_index { |i, j| yield @data [ i] [ j] , i, j }
end
def to_a
@data .flatten
end
def lose?
each_with_index.all ? do |n, i, j|
n && @data [ i] [ j + 1 ] != n && ( i >= @size - 1 || @data [ i + 1 ] [ j] != n)
end
end
def win?
any? { |n| n && n >= @max }
end
private
def move_left
@data .each do |row|
row.compact !
( @size - 1 ) .times do |i|
if row[ i] && row[ i] == row[ i + 1 ]
row[ i] = merge_value( row[ i] )
row.delete_at ( i + 1 )
end
end
row.push ( nil ) until row.size >= @size
end
end
def move_right
reverse { move_left }
end
def move_up
transpose { move_left }
end
def move_down
transpose { move_right }
end
def transpose
@data = @data .transpose
yield
ensure
@data = @data .transpose
end
def reverse
@data .each ( &:reverse!)
yield
ensure
@data .each ( &:reverse!)
end
def generate
i, j = each_index.select { |m, n| @data [ m] [ n] .nil ? } .sample
@data [ i] [ j] = first_value if i
end
def first_value
rand < 0.8 ? 2 : 4
end
def merge_value( n)
n * 2
end
end
class Game2048
include Enumerable
attr_reader :size
def initialize( size = 4 , max = 2048 )
@size , [ url=home.php ?mod=space&uid=25307 ] @Max[ /url] = size, max
@data = Array .new ( size) { Array .new ( size) }
2 .times { generate }
end
def move( direction)
last = to_a
send :"move_#{direction}"
return if last == to_a
generate
self
end
def [ ] ( i, j)
@data [ i] [ j]
end
def each
return to_enum( __method__) { @size **2 } unless block_given?
@data .each { |row| row.each { |n| yield n } }
end
def each_index
return to_enum( __method__) { @size **2 } unless block_given?
@size .times { |i| @size .times { |j| yield i, j } }
end
def each_with_index
return to_enum( __method__) { @size **2 } unless block_given?
each_index { |i, j| yield @data [ i] [ j] , i, j }
end
def to_a
@data .flatten
end
def lose?
each_with_index.all ? do |n, i, j|
n && @data [ i] [ j + 1 ] != n && ( i >= @size - 1 || @data [ i + 1 ] [ j] != n)
end
end
def win?
any? { |n| n && n >= @max }
end
private
def move_left
@data .each do |row|
row.compact !
( @size - 1 ) .times do |i|
if row[ i] && row[ i] == row[ i + 1 ]
row[ i] = merge_value( row[ i] )
row.delete_at ( i + 1 )
end
end
row.push ( nil ) until row.size >= @size
end
end
def move_right
reverse { move_left }
end
def move_up
transpose { move_left }
end
def move_down
transpose { move_right }
end
def transpose
@data = @data .transpose
yield
ensure
@data = @data .transpose
end
def reverse
@data .each ( &:reverse!)
yield
ensure
@data .each ( &:reverse!)
end
def generate
i, j = each_index.select { |m, n| @data [ m] [ n] .nil ? } .sample
@data [ i] [ j] = first_value if i
end
def first_value
rand < 0.8 ? 2 : 4
end
def merge_value( n)
n * 2
end
end
作者: 化螺耕 时间: 2014-3-27 14:54
沙发了 过来膜拜大神 早就听说这个游戏很好玩了,虽然我是没有玩过啦
作者: taroxd 时间: 2014-3-27 18:46
本帖最后由 taroxd 于 2014-3-30 13:11 编辑
看了一下楼主的代码
draw_box方法为什么不用循环?
另外,失败条件并不是场上没有空格,还是无法进行下一次的移动
欢迎楼主直接用2L的代码做这个场景,我觉得会好很多。公有方法都写在上面了。(我是用nil来表示空格子的)
如果要使用的话,把每个 to_enum 后面跟的{ @size ** 2 } 去掉。这个block是给ruby2.0用的
作者: taroxd 时间: 2014-3-30 16:03
本帖最后由 taroxd 于 2014-3-31 18:45 编辑
def draw_box
for i in 0 ...4
for j in 0 ..4
if @game2048 .[ ] ( i, j) != nil
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , @game2048 .[ ] ( i, j) , 1 )
end
end
end
end
def draw_box
for i in 0 ...4
for j in 0 ..4
if @game2048 .[ ] ( i, j) != nil
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , @game2048 .[ ] ( i, j) , 1 )
end
end
end
end
汗,明明定义了each_with_index还这样玩……而且j的范围还打错了(虽然没什么大碍)
美观大方~
def draw_box
@game2048 .each_with_index do |n, i, j|
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , n, 1 ) if n
end
end
def draw_box
@game2048 .each_with_index do |n, i, j|
@background_sprite .bitmap .draw_text ( 130 +80 *j, 100 +60 *i, 60 , 24 , n, 1 ) if n
end
end
另外 @game2048.[](i, j) 写成 @game2048[i, j] 就好
还有update方法可以写简单点, 改起来也方便~ 比如加个移动失败的功能
def update
super
[ :left , :right , :up , :down ] .each do |dir|
if Input.trigger ? dir.upcase
if @game2048 .move dir
judge
clear_box
Sound.play_cursor
draw_box
else
Sound.play_buzzer # 移动失败
end
end
end
end
def update
super
[ :left , :right , :up , :down ] .each do |dir|
if Input.trigger ? dir.upcase
if @game2048 .move dir
judge
clear_box
Sound.play_cursor
draw_box
else
Sound.play_buzzer # 移动失败
end
end
end
end
然后,如果要加得分功能的话,可以对merge_value重定义,来增加@score即可
当然score要初始化为零,并且做好attr_reader :score
作者: alpacanist 时间: 2014-3-30 19:16
仰望,话说RM的键盘操作特适合移植这个啊,不过不知道能不能加入让使用者自定义文字信息的功能?目前扫了一眼,似乎……没发现orz
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1