StarRubyで波紋生成シミュレーション

D

実行ファイル:RippleSimulator.exe 直

#######################################################################
#
#    DESCRIPTION:	タスクシステム管理
#    AUTHOR:		shom
#    DATE:		2012/10/13
#
#######################################################################

require "starruby"
include StarRuby

class Task
	def exec( tex, keys, mouse, mouseLocat )
		#virtual
	end
end

load "Ripple.rb"


# 中間レンダリングバッファ生成
midTex = Texture.new( 480, 480 )

# タスク生成
# -タスクリスト
HashTask = Hash.new

# -移動体
HashTask.store( :ripple, Ripple.new(midTex) )


# フォント生成
font = Font.new( "MS UI Gothic", 20 )
font_color = Color.new( 255, 255, 255 )


# ゲームループ
w = midTex.width()
h = midTex.height()
title = "Ripple Simulator ( powered by StarRuby )"

Game.run( w, h, :cursor => true, :fps => 15, :title => title ) do |game|

	# 中間バッファリセット
	midTex.clear

	# 入力受付
	keys = Input.keys( :keyboard )
	mouse = Input.keys( :mouse )
	mouseLocat = Input.mouse_location()

	# ESCキーで中断
	break if keys.include?( :escape )

	# タスク毎時処理
	HashTask.each_value do |task|
		task.exec( midTex, mouse, mouseLocat )
	end

	# 中間バッファ反映
	game.screen.clear
	game.screen.render_texture( midTex, 0, 0 )

	# デバッグテキスト出力
	debug_text = ""
	debug_text << "[ fps ( ideal : ";
	debug_text << game.fps().to_i().to_s();
	debug_text << " ) ] : ";
	debug_text << game.real_fps().to_i().to_s();
	game.screen.render_text( debug_text, 8, 8, font, font_color )

	debug_text = "[ produce ripple ] : ";
	if mouse.include?( :left )
		debug_text << "on"
	else
		debug_text << "off"
	end
	game.screen.render_text( debug_text, 8, 8 + 24, font, font_color )

	debug_text = "[ update ] : ";
	if mouse.include?( :right )
		debug_text << "stopping"
	else
		debug_text << "working"
	end
	game.screen.render_text( debug_text, 8, 8 + 24 * 2, font, font_color )

	if mouse.include?( :middle )
		game.screen.render_text( "CLEAR!", 240 - 24 / 2 * 3, 240 - 24 / 2, font, font_color )
	end
end
#######################################################################
#
#    DESCRIPTION:	波紋生成
#    AUTHOR:		shom
#    DATE:		2012/10/13
#
#######################################################################

require "starruby"
include StarRuby

class Ripple < Task

	#定数
	GRID_HEIGHT = 6
	GRID_WIDTH = 6
	ATTENUATION = 0.999 #減衰率(1に限りなく近いほど、波の伝搬力が高くなる)

	def initialize(tex)

		@xmax = ( (tex.width())/GRID_WIDTH ).floor()
		@ymax = ( (tex.height())/GRID_HEIGHT ).floor()

		@heightTbl = Array.new
		@heightPrevTbl = Array.new
		for y in 0..(@ymax-1)
			for x in 0..(@xmax-1)
				@heightTbl.push( 0 )
				@heightPrevTbl.push( 0 )
			end
		end
	end

	# 関数:色情報獲得:クリア
	def getHeightClear(tex, elColors = @heightTbl)

		for y in 0..(@ymax-1)
			for x in 0..(@xmax-1)
				@heightTbl[y*@xmax+x] = 0
				@heightPrevTbl[y*@xmax+x] = 0
			end
		end
	end

	# 関数:色情報獲得:マウスの位置を黒に
	def getHeightMouse(tex, mouse, mouseLocat)		

		#マウスの位置を高さを最大にする
		if mouse.include?( :left ) then
			x,y = mouseLocat

			idxX = (x/GRID_WIDTH).floor
			idxY = (y/GRID_HEIGHT).floor

			idx = idxY * @xmax + idxX

			@heightTbl[ idx ] = 100
		end
	end

	# 関数:色情報に波の効果を出す
	def effectRipple(tex)
		
		# バッファ確保
		nextHeightTbl = Array.new(@heightTbl)

		# 
		for y in 0..(@ymax-1)
			for x in 0..(@xmax-1)

				surroundSum = 0

				if x!=0
					surroundSum += @heightTbl[y*@xmax+(x-1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if x!=(@xmax-1)
					surroundSum += @heightTbl[y*@xmax+(x+1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if y!=0
					surroundSum += @heightTbl[(y-1)*@xmax+x]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if y!=(@ymax-1)
					surroundSum += @heightTbl[(y+1)*@xmax+x]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if x!=0 and y!=0
					surroundSum += @heightTbl[(y-1)*@xmax+(x-1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if x!=(@xmax-1) and y!=0
					surroundSum += @heightTbl[(y-1)*@xmax+(x+1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if x!=0 and y!=(@ymax-1)
					surroundSum += @heightTbl[(y+1)*@xmax+(x-1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				if x!=(@xmax-1) and y!=(@ymax-1)
					surroundSum += @heightTbl[(y+1)*@xmax+(x+1)]
				else
					surroundSum += @heightTbl[y*@xmax+x]
				end

				difSurround = ( surroundSum / 8 * ATTENUATION - @heightTbl[y*@xmax+x] )
				difCenter = @heightTbl[y*@xmax+x] - @heightPrevTbl[y*@xmax+x]

				nextHeight = @heightTbl[y*@xmax+x] + difSurround + difCenter
	
				if nextHeight > 100 then 
					nextHeight = 100
				elsif nextHeight < 0 then
					nextHeight = 0
				end

				nextHeightTbl[y*@xmax+x] = nextHeight
			end
		end

		# 色情報更新
		@heightPrevTbl = @heightTbl.clone
		@heightTbl	= nextHeightTbl.clone
	end


	# 関数:描画
	def renderRect(tex)

		heightTbl = @heightTbl.clone

		# 矩形を並べる
		0.step(tex.height()-1, GRID_HEIGHT) do |y|
			0.step(tex.width()-1, GRID_WIDTH) do |x|
				height = ( heightTbl.shift() ).floor
				color = Color.new( 0, 0, 255 * height / 100 )
				tex.render_rect(x, y, GRID_WIDTH, GRID_HEIGHT, color)
			end
		end
	end

	# 関数:毎時処理
	def exec(tex, mouse, mouseLocat)

		# 色情報を獲得
		if mouse.include?( :middle ) then
			getHeightClear(tex, @heightTbl)
			getHeightClear(tex, @heightPrevTbl)
		else
			getHeightMouse(tex, mouse, mouseLocat)
		end

		# 色情報に波の効果を出す
		if !mouse.include?( :right ) then
			effectRipple(tex)
		end

		# 矩形を色情報を使って描画
		renderRect(tex)
	end
end