【Ruby】用ruby在3D软件Sketchup中开发贪吃蛇小游戏
sketchup是非常简单易用的三维建模软件,可以利用ruby 做二次开发,
今天在su中做了一款小游戏 贪吃蛇,说一下步骤
展示
主要思路:
我制作的的玩法是这样的
关于入口文件
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 入口文件 require 'json' require_relative 'help.rb' # 帮助文件 module NaiveSnake $game = nil # 用于保存蛇类实例变量 class Index @@dig = nil @@setDig = nil @@lydig = nil def initialize cmd = UI::Command.new("NaiveSnake") { # 主窗口 @@dig = UI::WebDialog.new "NaiveSnake", false, "", 229, 172, 5, 90, false @@dig.set_file __dir__+'/index.html' # 设置窗口 @@setDig = UI::WebDialog.new "NaiveSnake_set", false, "", 262, 315, 235, 90, false @@setDig.set_file __dir__+'/set.html' # 排行窗口 @@lydig = UI::WebDialog.new "NaiveSnake_琅琊榜", false, "", 290, 320, 5, 260, false @@lydig.set_url 'http://00a00.com/snake/' @@dig.show if not @@dig.visible? @@dig.add_action_callback 'start' do # 检测是否有模型 if Sketchup.active_model.active_entities.length > 0 is = UI.messagebox("检测到有模型存在,是否清空?\r\n(注:清空才可进入游戏)",MB_YESNO) if is == 6 Sketchup.active_model.active_entities.clear! load __dir__+'/Base.rb' require_relative 'Camera.rb' require_relative 'Map.rb' load __dir__+'/Food.rb' load __dir__+'/Snake.rb' load __dir__+'/SnakeTool.rb' Camera.new # 初始化相机 Map.new.show # 显示场景 Food.new.show # 显示食物 $game = Snake.new # 蛇实例 $game.start # 开始游戏 Sketchup.active_model.select_tool SnakeTool.new # 选择工具 @@dig.close if @@dig.visible? # 关闭窗口 @@setDig.close if @@dig.visible? # 关闭窗口 @@lydig.close if @@dig.visible? # 关闭窗口 else next end end end # ready @@dig.add_action_callback 'ready' do # 生成随机名字 len = 8 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a newpass = "" 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] } config 'nickname', newpass end # 设置按钮 @@dig.add_action_callback 'set' do @@setDig.show end # 琅琊榜 @@dig.add_action_callback 'langYa' do @@lydig.show end # 确认按钮 @@setDig.add_action_callback('ok'){|dig, json| hash = JSON.parse json hash.each{|k, v| config k, v } dig.close } # 默认按钮 @@setDig.add_action_callback('rec'){|dig, json| json = configRec() @@setDig.execute_script "fill(#{json})" } # 页面刷新 @@setDig.add_action_callback('init'){|dig, json| json = configAll() @@setDig.execute_script "data = #{json}" } } # 工具栏 cmd.small_icon = cmd.large_icon = __dir__+"/assets/icon.png" cmd.menu_text = "NaiveSnake" toolbar = UI::Toolbar.new "NaiveSnake" toolbar = toolbar.add_item cmd toolbar.show # 菜单 menu = UI.menu('Plugins').add_submenu('NaiveSnake(贪吃蛇)') menu.add_item end end end NaiveSnake::Index.new
初始化基类
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 基类 module NaiveSnake class Base @@model = Sketchup.active_model # 模型 @@view = @@model.active_view # 视 @@ent = @@model.active_entities # 实体 @@mat = @@model.materials # 材质 @@mapWidth = config('mapWidth').to_i # 地图宽 @@mapHeight = config('mapHeight').to_i # 地图高 @@snakeHeight = config('snakeHeight').to_i # 蛇高度 @@snakeWidth = config('snakeWidth').to_i # 蛇宽度 @@snakeNums = config('snakeNums').to_i # 蛇身数 @@level = config('级别') # 级别 @@direction = UP # 初始方向 @@currentSnake = [] # 当前蛇body @@snakeArr = [] # 出生蛇body @@foot = [] # 储存食物 @@blackList = [] # 食物黑名单 @@time_id = nil # 定时器 @@score = 0 # 分数 end end
初始化相机
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 相机类 module NaiveSnake class Camera < Base def initialize start end def start eye = [0, 0,1300]; target = [0,0,0]; up = [0,1,0] start_camera = Sketchup::Camera.new eye, target, up @@view.camera = start_camera end end end
初始化场景
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 场景类 module NaiveSnake class Map < Base def show grassland # 草地 end def grassland filename = __dir__+'/assets/grassland.skm' material = @@mat.load(filename) pt1 = Geom::Point3d.new -@@mapWidth/2, -@@mapHeight/2, 0 pt2 = Geom::Point3d.new @@mapWidth/2, -@@mapHeight/2, 0 pt3 = Geom::Point3d.new @@mapWidth/2, @@mapHeight/2, 0 pt4 = Geom::Point3d.new -@@mapWidth/2, @@mapHeight/2, 0 grp = @@ent.add_group grp.entities.add_face pt1, pt2, pt3, pt4 grp.material = material end end end
初始化蛇类
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 蛇类 module NaiveSnake class Snake < Base def initialize @@snakeArr = initSnake @@snakeNums @up = 38; @down = 40; @left = 37; @right = 39 @direction = @@direction @x = rand(-@@mapWidth..@@mapWidth)/2/10*10 @y = rand(-@@mapHeight..@@mapHeight)/2/10*10 end def start createSnake # 绘制蛇 speed = 0.5 case @@level when '普通'; speed = 0.4 when '勇士'; speed = 0.1 when '地狱'; speed = 0.03 when '噩梦'; speed = 0.006 end time = 1 @@time_id = UI.start_timer(speed, true) do move(@direction) time += 1 end end def set(direction) @direction = direction end # 绘制蛇 def createSnake @@currentSnake.clear # 清空蛇当前状态 @@snakeArr.each do |box| xBaseValue = @@snakeWidth/2 yBaseValue = @@snakeWidth/2 point1 = Geom::Point3d.new(box[0]-xBaseValue, box[1]-yBaseValue, 0) point2 = Geom::Point3d.new(box[0]+xBaseValue, box[1]-yBaseValue, 0) point3 = Geom::Point3d.new(box[0]+xBaseValue, box[1]+yBaseValue, 0) point4 = Geom::Point3d.new(box[0]-xBaseValue, box[1]+yBaseValue, 0) boxGroup = @@ent.add_group face = boxGroup.entities.add_face point1, point2, point3, point4 face.reverse!.pushpull @@snakeHeight @@currentSnake.push boxGroup # 重新设置蛇身体 end end # 移动 def move(direction) tmpArray = [] # 临时容器 head = @@snakeArr.last # 蛇头 # 判断蛇头是否碰到黑名单 @@blackList.each{|list| if head == list # Game Over gameOver return end } #判断蛇头是否碰到边缘 if head[0].abs >= @@mapWidth/2 || head[1].abs >= @@mapHeight/2 gameOver return end # 判断蛇头是否碰到食物 if head == @@foot # 加分 @@score += 10 # 将食物列入黑名单 @@blackList.push @@foot # 蛇头随机移动 @x = rand(-(@@mapWidth-50)..@@mapWidth-50)/2/10*10 @y = rand(-@@mapHeight..@@mapHeight)/2/10*10 @@snakeArr.push [@x+@@snakeWidth/2, @y+@@snakeHeight/2] # 再次显示食物 Food.new.show end # 移动数组前一位 lastValue = @@snakeArr.last.clone; for i in 0...@@snakeArr.size-1 tmpArray[i] = @@snakeArr[i+1] end tmpArray.push(lastValue) case direction when @up; tmpArray.last[1] += @@snakeWidth when @down; tmpArray.last[1] -= @@snakeWidth when @right; tmpArray.last[0] += @@snakeWidth when @left; tmpArray.last[0] -= @@snakeWidth end @@snakeArr = tmpArray # 重新设置蛇body deleteSnake # 删除 createSnake # 再次绘制 end def deleteSnake @@currentSnake.each do |ent| ent.entities.each{|ent| @@ent.erase_entities ent} end # 删除原来 end def gameOver UI.stop_timer @@time_id UI.messagebox "游戏结束!\r\n得分:"+@@score.to_s updateScore # 更新分数 end def updateScore hash = { :nickname => config('nickname'), :score => @@score, :level => config('级别'), :tk => 'qwertyuioplkjhgfdsazxcvbnm', } request = Sketchup::Http::Request.new("http://00a00.com/snake/save.php", Sketchup::Http::POST) request.body= httpBuild(hash) request.start do |request, response| p '琅琊榜更新成功' if response end end def httpBuild(hash) str = '' hash.each{|k, v| str+= k.to_s+'='+v.to_s+'&' } str.chop! end def initSnake(n) array = [] n.times{|i| array.push [@@snakeWidth/2+@@snakeWidth*i, @@snakeWidth/2] next if i == 0 } array end end end
初始化食物类
# ----------------------------- # # email:bc8web@126.com # # ------------------------------# # 食物类 module NaiveSnake class Food < Base def initialize @x = rand(-@@mapWidth..@@mapWidth)/2/10*10 @y = rand(-@@mapHeight..@@mapHeight)/2/10*10 end def show filename = __dir__+'/assets/food.skm' material = @@mat.load(filename) point = [] unless isFull? point[0] = [@x, @y, 0] point[1] = [@x+@@snakeWidth, @y, 0] point[2] = [@x+@@snakeWidth, @y+@@snakeWidth, 0] point[3] = [@x, @y+@@snakeWidth, 0] group = @@ent.add_group @@foot = [@x+@@snakeWidth/2, @y+@@snakeHeight/2] face = group.entities.add_face point face.material = material face.reverse!.pushpull @@snakeHeight @foot = face else @x = rand(-@@mapWidth..@@mapWidth) @y = rand(-@@mapHeight..@@mapHeight) end end def isFull? return @@snakeArr.include? [@x, @y] end end end