📜 ⬆️ ⬇️

Corona SDK - Crush Crush Game

image

We write a simple but very exciting game. The game is called Crush it will need to crush insects, trying to avoid the pressure of the OS, as they take away points, other insects add points. All insects have different dimensions of size, reward and speed of movement. The game is given a certain time so in the skill of the pressure of the correct animals you can easily compete with friends. The best result is recorded and saved in the game settings.


Project Settings


All project settings are contained in the config.lua and build.settings files. I decided to delete the entire contents of config.lua, leaving only the line:

application = {
}


Now the project is trying to “think” on any device that the screen has a fixed size of 320 * 480 (as it was by default), we always work with the current screen resolution. In the build.settings file, I added a new permission to the settings.android.usesPermissions section that gives the right to buzz with a vibrating signal when touching the wasps, the following line was added: “android.permission.VIBRATE” , and the system.vibrate () line of code uses these rights.
')

Entry point main.lua


The theater begins with a hanger, and the project in the crown begins with the first line of the main.lua file. In this file, it is customary to store global variables and constants, as well as connect to the project the remaining files that will be needed in the project. At the end of the file, the main project scene is loaded.

The full code of the main.lua file is:

 --[[ ]] -- StatusBar display.setStatusBar (display.HiddenStatusBar) --[[ ]] --  _W = display.contentWidth _H = display.contentHeight font = 'a_LCDNova'--  time_battle = 10--  --   filePath = system.pathForFile( 'config.dat', system.DocumentsDirectory ) composer = require("composer")--    --   path = 'assets/images/' path_interface = path .. 'interface/' path_bugs = path .. 'bugs/' path_plods = path .. 'plods/' --    widget = require( "widget" )--GUI  ls = require "libLoadSave"--/  api = require "libAPI"--  bugs = require "svcBugs"--   finish = require "svcFinish"--  "" game = require "svcGame"--   battle = nil--  ls.load() --      --  game.init()      --scMain ,       composer.gotoScene( "scMain", "crossFade", 0 ) 


Main stage


The scMain.lua file is the main scene of the game. In this project, its use is doubtful, since there is only one scene, but the project is educational and the scene can be useful if you decide to add more scenes in your experiments. In the main scene, only one action is performed — launch the init () function from the libGame library. And then this function draws the entire permanent interface of the game, i.e. those parts that will not be deleted until the end of using the application. The file code is:

 --------------------------------------- --      -- --------------------------------------- local scene = composer.newScene() scene:addEventListener( "show", scene ) function scene:show( event ) if "will" == event.phase then game.init() end end return scene 

Service static game components.


This service is stored in the svcGame.lua file and its connection to the project is performed by the line in main.lua: game = require “svcGame” ie Further along the code for calling library functions we add to the name game. The library has the following functions:


Full svcGame.lua code:

 ------------------------------------------------------- --      -- ------------------------------------------------------- local M = { GR = {},--  GUI = {},--  } --    M.startGame = function(event) if event.phase == 'ended' then --   battle.timer = time_battle battle.cur_score = 0 M.refresh() --  timer.performWithDelay(100, function(event) if event.count%10==0 then-- 10-  --    battle.timer = battle.timer - 1 M.refresh() end if event.count%2==1 then--   --  bugs.create(M.GR.bugs) end if event.count == time_battle*10 then--    --     finish.show() end end,time_battle*10) end end --    M.refresh = function() --   M.GUI.txt_count.text = battle.cur_score --  M.GUI.txt_best.text = battle.best_score ---     M.GUI.pr_txt.text = battle.timer --  M.GUI.pr.width = _W * .79 * (time_battle - battle.timer) / time_battle M.GUI.pr.x = _W * .105 + M.GUI.pr.width * .5 --       0 M.GUI.pr.isVisible = battle.timer > 0 M.GUI.pr_txt.isVisible = battle.timer > 0 M.GUI.pr_bg.isVisible = battle.timer > 0 --       0 M.GUI.btn_start.isVisible = battle.timer == 0 end --  M.init = function() --  M.GR.back = display.newGroup()--   M.GR.bugs = display.newGroup()--   M.GR.front = display.newGroup()--   --[[ ]] -- M.GUI.bg = display.newImage(M.GR.back,path_interface..'bg.jpg', _W*.5, _H * .5) M.GUI.bg.width = _W M.GUI.bg.height = _H --[[ ]] --   M.GUI.up = display.newRect(M.GR.front, _W * .5, _H * .05, _W, _H * .1) M.GUI.up.strokeWidth = _H * .01 M.GUI.up:setStrokeColor(0,.5,0) M.GUI.up:setFillColor(0,.3,0) M.GUI.up:addEventListener('touch', function() return true end)--     --      M.GUI.img_count = display.newImage(M.GR.front, path_interface..'count.png', _H * .06, _H * .05) local img = M.GUI.img_count img.width = _H * .07 img.height = _H * .07 --      M.GUI.txt_count = display.newText(M.GR.front, '', _W * .3, _H * .05, font, _W * .1) --   M.GUI.img_best = display.newImage(M.GR.front, path_interface..'best.png', _W * .5 + _H * .06, _H * .05) local img = M.GUI.img_best img.width = _H * .07 img.height = _H * .07 --text   M.GUI.txt_best = display.newText(M.GR.front, '', _W * .8, _H * .05, font, _W * .1) --   M.GUI.down = display.newRect(M.GR.front, _W * .5, _H * .95, _W, _H * .1) M.GUI.down.strokeWidth = _H * .01 M.GUI.down:setStrokeColor(0,.5,0) M.GUI.down:setFillColor(0,.3,0) M.GUI.down:addEventListener('touch', function() return true end) --  M.GUI.btn_start = widget.newButton( { width = _H * .07, height = _H * .07, defaultFile = path_interface .. "btn_start_1.png", overFile = path_interface .. "btn_start_2.png", onEvent = M.startGame, x = _W * .5, y = _H * .95, } ) --  --   M.GUI.pr_bg = display.newRoundedRect(M.GR.front, _W * .5, _H * .95, _W * .8, _H * .04, _H * .01) M.GUI.pr_bg.strokeWidth = _H * .005 M.GUI.pr_bg:setStrokeColor(0,.5,0) M.GUI.pr_bg:setFillColor(.4,.7,.4) --  M.GUI.pr = display.newRoundedRect(M.GR.front, _W * .5, _H * .95, _W * .79, _H * .035, _H * .006) M.GUI.pr:setFillColor(.7,.1,.1) --       M.GUI.pr_txt = display.newText(M.GR.front, '', _W * .5, _H * .955, font, _W * .07) M.GUI.pr_txt:setFillColor(0) --   M.refresh() end return M 

Insect creation service


The service has several components that serve the ability to conveniently create living creatures in the game:


The service code svcBugs.lua is:

 ------------------------------------------------ --    , -- --      -- --      -- ------------------------------------------------ local M = { GR = {},-- bugs = {--  -- { size = {20,30},--  - %   bonus = 2,--   file = '1.png',--   speed = {30,50},--   - %     }, -- { size = {25,35}, bonus = 3, file = '2.png', speed = {50,70}, }, --  { size = {15,25}, bonus = 3, file = '3.png', speed = {40,60}, }, -- { size = {20,30}, bonus = 6, file = '4.png', speed = {60,80}, }, -- { size = {35,50}, bonus = -10,--  =  file = '5.png', speed = {25,50}, }, }, AR_BUGS = {},--    } --  M.plod = function(obj) local count_plod = 3--   --   local blod = display.newImage(M.GR, path_plods..math.random(count_plod)..'.png',obj.x, obj.y) --      blod.width = obj.width blod.height = obj.height --  (  ) blod:setFillColor(math.random(),0,math.random()) --   transition.to(blod,{time = 500, alpha = 0, onComplete = function() --     display.remove(blod) end}) end --  M.create = function(GR) M.GR = GR and GR or M.GR --    local sets = M.bugs[math.random(#M.bugs)] --    local bug_sets = { file = sets.file, bonus = sets.bonus, size = (math.random(sets.size[1],sets.size[2]) / 100) * _W, speed = (math.random(sets.speed[1],sets.speed[2]) / 100) * _W, } --      local ar = {--       2  {x1 = 0, y1 = 0, x2 = _W, y2 = 0}, -- {x1 = 0, y1 = _H, x2 = _W, y2 = _H}, -- {x1 = -_H*.1, y1 = _H*.1, x2 = -_H*.1, y2 = _H*.9}, -- {x1 = _H*1.1, y1 = _H*.1, x2 = _H*1.1, y2 = _H*.9}, -- } -- 2  local l1,l2 = math.random(#ar),math.random(#ar) if l1 == l2 then if l2 == 1 then l2 = math.random(2,#ar) else l2 = l2 - 1 end end --   local x1,y1 = api.get_xy_line(ar[l1]) local x2,y2 = api.get_xy_line(ar[l2]) --  local n = #M.AR_BUGS+1 M.AR_BUGS[n] = display.newImage(M.GR, path_bugs..bug_sets.file, 0, 0) M.AR_BUGS[n].width = bug_sets.size M.AR_BUGS[n].height = bug_sets.size M.AR_BUGS[n].x = x1 M.AR_BUGS[n].y = y1 M.AR_BUGS[n].sets = bug_sets M.AR_BUGS[n].rotation = api.get_angle{x1 = x1, y1 = y1, x2 = x2, y2 = y2}--    M.AR_BUGS[n]:addEventListener('touch',function(event) if event.phase == 'began' then api.play_sound('tits') M.plod(event.target) local sets = event.target.sets battle.cur_score = battle.cur_score + sets.bonus if sets.bonus < 0 then--    system.vibrate()--;) end game.refresh() M.create() display.remove(event.target) end return true end) --    local len = api.get_line_len{x1 = x1, y1 = y1, x2 = x2, y2 = y2}--  local t = len / bug_sets.speed * 1000--   transition.to(M.AR_BUGS[n],{time = t, x = x2, y = y2, onComplete = function() display.remove(M.AR_BUGS[n]) end}) end return M 

Service "Finish"


This simple service has only one function, finish.show (), which is called in the battle timer when the end of the battle is reached. This function removes all insects and opens the form with the output of the result. If the result is higher than the past, the text “NEW SCORE” is displayed. Under the form, a protective layer is created that does not allow the game to be restarted until the window is closed. When you click on the window, it closes the result of saving to the settings file. Service code is:

 ------------------------------------------------ --       -- ------------------------------------------------ local M = { GUI = {}, GR = {}, } --  M.show = function() api.play_sound('win') --   for k,v in pairs(bugs.AR_BUGS) do display.remove(bugs.AR_BUGS[k]) end --    local is_new_score = battle.cur_score > battle.best_score if is_new_score then battle.best_score = battle.cur_score end --    M.GR = display.newGroup() --   M.GUI.safe = display.newRect(M.GR, _W * .5, _H * .5, _W, _H) M.GUI.safe.alpha = .5 M.GUI.safe:setFillColor(0) M.GUI.safe:addEventListener('touch', function() return true end) --     M.GUI.wnd = display.newRoundedRect(M.GR, _W * .5, _H * .5, _W * .5, _H * .2, _H * .01) M.GUI.wnd.strokeWidth = _H * .005 M.GUI.wnd:setStrokeColor(0,.5,0) M.GUI.wnd:setFillColor(0,.3,0) M.GUI.wnd:addEventListener('touch',function(event) if event.phase == 'began' then display.remove(M.GR) end end) M.GUI.txt_1 = display.newText(M.GR, 'FINISH', _W * .5, _H * .45, font, _W * .07) M.GUI.txt_2 = display.newText(M.GR, 'NEW SCORE', _W * .5, _H * .5, font, _W * .07) M.GUI.txt_2:setFillColor(1,1,0) M.GUI.txt_2.isVisible = is_new_score M.GUI.txt_2 = display.newText(M.GR, 'SCORE: '..battle.cur_score, _W * .5, _H * .55, font, _W * .07) game.refresh() ls.save()--  end return M 

Library of storing and loading settings


This simple library contains two functions that allow you to store the result between gaming sessions.


Settings are stored in the config.dat file in json format. The library code is:

 ------------------------------------- --    -- --     -- ------------------------------------- local M = {} local json = require("json") M.tmp_battle = { cur_score = 0,--  best_score = 0,--  timer = 0,--    } --     M.save = function(new) local file = io.open(filePath, "w") if file then local write_data = '' write_data = json.encode(battle) file:write( write_data ) io.close( file ) end end --     M.load = function() local str = "" local file = io.open( filePath, "r" ) --   if file then local read_data = file:read("*a") battle = json.decode(read_data) io.close( file ) --   else battle = M.tmp_battle M.save() end end return M 

Library of universal functions.

Here all the functions that are needed in the game are stored but explicitly do not apply to any module and can later be used for other purposes. The following functions are available:


 --------------------------------------------------- --      -- --------------------------------------------------- local M = {} --  M.play_sound = function(track) local msg = audio.loadSound("assets/music/" .. track .. ".wav") audio.play( msg,{ loops = 0, oncomplete = function(e) audio.dispose(e.handle); e.handle = nil; end}) end --  ,        M.get_xy_line = function(line) local x1,y1,x2,y2 = line.x1,line.y1,line.x2,line.y2 local x,y = 0,0 if x1 == x2 then x = x1 y = math.random(y1,y2) else y = y1 x = math.random(x1,x2) end return x,y end --  M.get_line_len = function(p) --√ ((X2-X1)²+(Y2-Y1)²) local len = math.sqrt((p.x2 - p.x1)^2 + (p.y2 - p.y1)^2) return len end --    M.get_angle = function(p) return ((math.atan2(p.y1 - p.y2, p.x1-p.x2) / (math.pi / 180)) + 270) % 360 end return M 

Conclusion


The full source of the game presented in the article you will find in here.

If your knowledge of the Lua language does not allow you to confidently read the source, you can read my article on this issue.

The article was prepared for you by Denis Goncharov aka execom
Good luck to all!

Source: https://habr.com/ru/post/344638/


All Articles