From 8d3e9096b4b2e6ff208d293d2bc2cea67e380f8a Mon Sep 17 00:00:00 2001 From: turanszkij Date: Thu, 2 May 2019 20:00:13 +0100 Subject: [PATCH] updated fighting game sample: improved fireball --- models/emitter_fireball.wiscene | Bin 0 -> 5762 bytes scripts/fighting_game.lua | 161 ++++++++++++++++++-------------- 2 files changed, 90 insertions(+), 71 deletions(-) create mode 100644 models/emitter_fireball.wiscene diff --git a/models/emitter_fireball.wiscene b/models/emitter_fireball.wiscene new file mode 100644 index 0000000000000000000000000000000000000000..1a13f448a380a052a408053eb4ab7d4d611cf981 GIT binary patch literal 5762 zcmcIoTWl3o6dgcXYz2xBkQSk$AgHv6g0|8*DJEn=8m95JsLJ{*|xQAeaHo|DfY;J5Y4u$Ohye#ZL`>HgO-<;_6 zIV=f&w@ulLr0V^xn?}{sFcYI~$olaL;FZB(lzy8JPl#d}MpwT-AAZ!=6o0eiSoXp@ zbF&z~ed|`XF|2XpZwzGrJX920pDBG!uIF%(pPPhA;@G*N*x!&ih;Mx?Zu~>*V{wx= z-1G4^U;f`xXJ*H~ENYuAIr3xo`jR-_ zuON;yKH;2Crh1=mD;k~Q!I@l6e0)9dG2__GjZH4?5#>eB^b$%hq4W}>7pVc7rH{>pUKq!jT%qvhgg4X+-dIm4 zYv*K5eN5|*j?fc+Y%UMqj$=LKNc>IBv5A@IWAoa%mS?*k?4D8om z)Y}xh#mBO#)Z8q_VvNt%)wtBPf$U2Mi(=~|b_War?J)SXL<>xmr&~TYalg%Tf~ipA7FkgHJ}&Yr__Koap+h0 z0S6Af7$4!S3H@SjWPEHc^ujpKGX6i~(1O}J_-A`cL&%FgdxfLOEz7idy?3z3%UPL0kGpig*CnNohqyO)uW++6 zZ9XpQKtALLF8M>~$Onl$37+vd@&QL4;1_#J{e0vDjy%B87i8JGw3nz4I_iNuyK0)p zk^jx+YUK42^G?=Ocy53%lsX|12RQPpzn6#$9QhMG<0bL{2YV~Ei z`+k5+-ywALo#?e*2OpRZo`8ct_<>LL^E%cC{b7y42l8Q^P={H5m`6OW7NC4y;KPzU zD*59cm3(3^QoUH^1eJX9;rm3X;(SY(sQM(8jL*1y>nKzE6qWa@d_d)cDj!lgRpm65 z{xw6!(^cmiP=)Hu%X~8wXI|!eL~-V2zL|p-0AP@{4D>y(U%bG>M%PQHm(>U{D? zJ8|v@+NqOg;@n5%k9OkRZ?sb<&&0V;$sg^+xu0pLPM(SLIv{`Cuf%!1&`zB^6X$hC z{%9x8>ydWqb>7d2lQ-@=@<)8U)=4{c-nWQPQa|!XJMoDHcIxDr^Gel^{LxOl zq`*#{JagUz^&@|@6E7~XQzy@y$A0A@#~Rd0* zBhL4Dofcf>Uoi=Pv~ z`LlBx=jV{f{XWp*sm$5%DXDVVuag_xnbW6*Ue-4J2s`}MkaKSSbGf(t%H>{2IqNUn zyj%~-uYkFHcQ<1E!dc{Vkc%hpfaB&LkUkeJ4t+{;u!=#E)RmPmGphR;mew&4kD1p>pjohtij96j~+Q9 t^>?k5IPU0?>9R+rqNlo4>MI!s!FRp&ONXvs_uHS>guwNub`1DS_Fte4Cj9^a literal 0 HcmV?d00001 diff --git a/scripts/fighting_game.lua b/scripts/fighting_game.lua index 1522115b7..8e57e6a21 100644 --- a/scripts/fighting_game.lua +++ b/scripts/fighting_game.lua @@ -34,6 +34,8 @@ local function Character(face, shirt_color) effect_hit = INVALID_ENTITY, effect_guard = INVALID_ENTITY, effect_spark = INVALID_ENTITY, + model_fireball = INVALID_ENTITY, + effect_fireball = INVALID_ENTITY, sprite_hpbar_background = Sprite(), sprite_hpbar_hp = Sprite(), sprite_hpbar_pattern = Sprite(), @@ -59,6 +61,15 @@ local function Character(face, shirt_color) hit_guard = false, -- true when opponent is guarding the attack max_hp = 10000, -- maximum health hp = 10000, -- current health + fireball_active = false, -- fireball is on screen or not + + -- Box helpers: + set_box_local = function(self, boxlist, aabb) -- sets box relative to character orientation + table.insert(boxlist, aabb.Transform(scene.Component_GetTransform(self.model).GetMatrix())) + end, + set_box_global = function(self, boxlist, aabb) -- sets box in absolute orientation + table.insert(boxlist, aabb) + end, -- Effect helpers: spawn_effect_hit = function(self, local_pos) @@ -107,36 +118,38 @@ local function Character(face, shirt_color) scene.Entity_Remove(entity) end) end, - spawn_effect_fireball = function(self, local_pos) -- todo - runProcess(function() -- first subprocess begins effects, and attaches light - scene.Component_GetEmitter(self.effect_hit).SetEmitCount(1000) - local transform_component = scene.Component_GetTransform(self.effect_hit) + spawn_effect_fireball = function(self, local_pos, velocity) -- todo + self.fireball_active = true + runProcess(function() -- first subprocess begins effect + scene.Component_GetEmitter(self.effect_fireball).SetEmitCount(2000) + local transform_component = scene.Component_GetTransform(self.model_fireball) transform_component.ClearTransform() transform_component.Translate(vector.Add(self.position, local_pos)) - transform_component.UpdateTransform() - - local entity = CreateEntity() - scene.Component_Attach(entity, self.effect_hit) - local light_transform = scene.Component_CreateTransform(entity) - light_transform.Translate(vector.Add(self.position, local_pos)) - local light_component = scene.Component_CreateLight(entity) - light_component.SetType(POINT) - light_component.SetRange(8) - light_component.SetEnergy(10) - light_component.SetColor(Vector(1,0.5,0)) - light_component.SetCastShadow(false) - - waitSignal("fireball_end") -- wait for fireball to end - scene.Entity_Remove(entity) - scene.Component_GetEmitter(self.effect_hit).SetEmitCount(0) + waitSignal("fireball_end" .. self.model) -- wait for fireball to end + scene.Component_GetEmitter(self.effect_fireball).SetEmitCount(0) + transform_component.Translate(Vector(0,0,-1000000)) end) runProcess(function() - for i=1,60,1 do -- move the fireball effect for some time - local transform_component = scene.Component_GetTransform(self.effect_hit) - transform_component.Translate(Vector(self.face * 0.2)) - waitSeconds(0.016) + for i=1,120,1 do -- move the fireball effect for some frames + local transform_component = scene.Component_GetTransform(self.model_fireball) + transform_component.Translate(velocity) + transform_component.UpdateTransform() + if(self:require_hitconfirm()) then + signal("fireball_end" .. self.model) -- end the first subprocess + self.fireball_active = false + return + end + waitSignal("subprocess_update" .. self.model) + end + signal("fireball_end" .. self.model) -- end the first subprocess + self.fireball_active = false + end) + runProcess(function() -- while there is a fireball, activate hitboxes + while(self.fireball_active) do + local transform_component = scene.Component_GetTransform(self.model_fireball) + self:set_box_global(self.hitboxes, AABB(Vector(-0.5,-0.5), Vector(0.5,0.5)).Transform(transform_component.GetMatrix()) ) + waitSignal("subprocess_update_collisions" .. self.model) end - signal("fireball_end") -- end the first subprocess end) end, spawn_effect_dust = function(self, local_pos) @@ -413,7 +426,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,8)), update_collision = function(self) if(self:require_window(3,6)) then - table.insert(self.hitboxes, AABB(Vector(0.5,2), Vector(3,5)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,2), Vector(3,5)) ) end end, update = function(self) @@ -432,7 +445,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,8)), update_collision = function(self) if(self:require_window(12,14)) then - table.insert(self.hitboxes, AABB(Vector(0.5,2), Vector(3.5,6)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,2), Vector(3.5,6)) ) end end, update = function(self) @@ -451,7 +464,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(8,10)), update_collision = function(self) if(self:require_window(3,6)) then - table.insert(self.hitboxes, AABB(Vector(0.5,2), Vector(3.5,5)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,2), Vector(3.5,5)) ) end end, update = function(self) @@ -470,7 +483,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,4)), update_collision = function(self) if(self:require_window(3,6)) then - table.insert(self.hitboxes, AABB(Vector(0.5,0), Vector(2.8,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,0), Vector(2.8,3)) ) end end, update = function(self) @@ -489,7 +502,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,8)), update_collision = function(self) if(self:require_window(6,8)) then - table.insert(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) end end, update = function(self) @@ -508,7 +521,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,8)), update_collision = function(self) if(self:require_window(8,13)) then - table.insert(self.hitboxes, AABB(Vector(0,0), Vector(4,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,0), Vector(4,3)) ) end end, update = function(self) @@ -527,7 +540,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,-6),Vector(6,8)), update_collision = function(self) if(self:require_window(6,8)) then - table.insert(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) end end, update = function(self) @@ -546,7 +559,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,-6),Vector(6,8)), update_collision = function(self) if(self:require_window(6,8)) then - table.insert(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,0), Vector(3,3)) ) end end, update = function(self) @@ -565,7 +578,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,4)), update_collision = function(self) if(self:require_window(3,6)) then - table.insert(self.hitboxes, AABB(Vector(0.5,0), Vector(3,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,0), Vector(3,3)) ) end end, update = function(self) @@ -584,7 +597,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(16,8)), update_collision = function(self) if(self:require_window(11,41)) then - table.insert(self.hitboxes, AABB(Vector(0.5,0), Vector(5.6,3)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0.5,0), Vector(5.6,3)) ) end end, update = function(self) @@ -610,7 +623,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(6,8)), update_collision = function(self) if(self:require_window(3,5)) then - table.insert(self.hitboxes, AABB(Vector(0,3), Vector(2.3,7)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,3), Vector(2.3,7)) ) end end, update = function(self) @@ -633,7 +646,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(16,8)), update_collision = function(self) if(self:require_window(17,40)) then - table.insert(self.hitboxes, AABB(Vector(0,1), Vector(4.5,5)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,1), Vector(4.5,5)) ) end end, update = function(self) @@ -655,7 +668,7 @@ local function Character(face, shirt_color) guardbox = AABB(Vector(-2,0),Vector(8,15)), update_collision = function(self) if(self:require_window(2,20)) then - table.insert(self.hitboxes, AABB(Vector(0,2), Vector(2.3,7)) ) + self:set_box_local(self.hitboxes, AABB(Vector(0,2), Vector(2.3,7)) ) end end, update = function(self) @@ -678,13 +691,15 @@ local function Character(face, shirt_color) hurtbox = AABB(Vector(-1.2), Vector(1.2, 5.5)), guardbox = AABB(Vector(-2,0),Vector(16,8)), update_collision = function(self) - if(self:require_window(17,40)) then - table.insert(self.hitboxes, AABB(Vector(0,1), Vector(4.5,5)) ) - end + self.velocity = Vector() end, update = function(self) if(self:require_frame(16)) then - self:spawn_effect_fireball(Vector(2.5 * self.face, 3.6, -1)) + local fireball_velocity = Vector(self.face * 0.2) + if(self.position.GetY() > 0) then + fireball_velocity.SetY(-0.1) + end + self:spawn_effect_fireball(Vector(2.5 * self.face, 3.4), fireball_velocity) end end, }, @@ -813,7 +828,7 @@ local function Character(face, shirt_color) { "StaggerStart", condition = function(self) return self:require_hurt() end, }, { "Shoryuken", condition = function(self) return self:require_motion_shoryuken("B") end, }, { "SpearJaunt", condition = function(self) return self:require_motion_qcf("B") end, }, - { "Fireball", condition = function(self) return self:require_motion_qcf("A") end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self:require_motion_qcf("A") end, }, { "Turn", condition = function(self) return self.request_face ~= self.face end, }, { "Walk_Forward", condition = function(self) return self:require_input("6") end, }, { "Walk_Backward", condition = function(self) return self:require_input("4") end, }, @@ -847,7 +862,7 @@ local function Character(face, shirt_color) { "StaggerStart", condition = function(self) return self:require_hurt() end, }, { "Shoryuken", condition = function(self) return self:require_motion_shoryuken("B") end, }, { "SpearJaunt", condition = function(self) return self:require_motion_qcf("B") end, }, - { "Fireball", condition = function(self) return self:require_motion_qcf("A") end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self:require_motion_qcf("A") end, }, { "CrouchStart", condition = function(self) return self:require_input("1") or self:require_input("2") or self:require_input("3") end, }, { "Walk_Backward", condition = function(self) return self:require_input("4") end, }, { "RunStart", condition = function(self) return self:require_input_window("656", 7) end, }, @@ -875,7 +890,7 @@ local function Character(face, shirt_color) { "RunEnd", condition = function(self) return not self:require_input("6") end, }, { "Shoryuken", condition = function(self) return self:require_motion_shoryuken("B") end, }, { "SpearJaunt", condition = function(self) return self:require_motion_qcf("B") end, }, - { "Fireball", condition = function(self) return self:require_motion_qcf("A") end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self:require_motion_qcf("A") end, }, { "JumpForward", condition = function(self) return self:require_input("9") end, }, { "CrouchStart", condition = function(self) return self:require_input("1") or self:require_input("2") or self:require_input("3") end, }, { "ForwardLightPunch", condition = function(self) return self:require_input("6A") end, }, @@ -891,7 +906,7 @@ local function Character(face, shirt_color) { "Guard", condition = function(self) return self:require_guard() and self:require_input("4") end, }, { "Shoryuken", condition = function(self) return self:require_motion_shoryuken("B") end, }, { "SpearJaunt", condition = function(self) return self:require_motion_qcf("B") end, }, - { "Fireball", condition = function(self) return self:require_motion_qcf("A") end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self:require_motion_qcf("A") end, }, { "Turn", condition = function(self) return self.request_face ~= self.face end, }, { "Walk_Forward", condition = function(self) return self:require_input("6") end, }, { "Walk_Backward", condition = function(self) return self:require_input("4") end, }, @@ -909,6 +924,7 @@ local function Character(face, shirt_color) Jump = { { "StaggerAirStart", condition = function(self) return self:require_hurt() and self.position.GetY() > 0 end, }, { "StaggerStart", condition = function(self) return self:require_hurt() end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self.position.GetY() > 3 and self:require_motion_qcf("A") end, }, { "AirHeavyKick", condition = function(self) return self.position.GetY() > 4 and self:require_input("D") end, }, { "AirKick", condition = function(self) return self.position.GetY() > 2 and self:require_input("C") end, }, { "FallStart", condition = function(self) return self.velocity.GetY() <= 0 end, }, @@ -916,6 +932,7 @@ local function Character(face, shirt_color) JumpForward = { { "StaggerAirStart", condition = function(self) return self:require_hurt() and self.position.GetY() > 0 end, }, { "StaggerStart", condition = function(self) return self:require_hurt() end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self.position.GetY() > 3 and self:require_motion_qcf("A") end, }, { "AirHeavyKick", condition = function(self) return self.position.GetY() > 4 and self:require_input("D") end, }, { "AirKick", condition = function(self) return self.position.GetY() > 2 and self:require_input("C") end, }, { "FallStart", condition = function(self) return self.velocity.GetY() <= 0 end, }, @@ -923,6 +940,7 @@ local function Character(face, shirt_color) JumpBack = { { "StaggerAirStart", condition = function(self) return self:require_hurt() and self.position.GetY() > 0 end, }, { "StaggerStart", condition = function(self) return self:require_hurt() end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self.position.GetY() > 3 and self:require_motion_qcf("A") end, }, { "AirHeavyKick", condition = function(self) return self.position.GetY() > 4 and self:require_input("D") end, }, { "AirKick", condition = function(self) return self.position.GetY() > 2 and self:require_input("C") end, }, { "FallStart", condition = function(self) return self.velocity.GetY() <= 0 end, }, @@ -930,6 +948,7 @@ local function Character(face, shirt_color) FallStart = { { "StaggerAirStart", condition = function(self) return self:require_hurt() and self.position.GetY() > 0 end, }, { "StaggerStart", condition = function(self) return self:require_hurt() end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self.position.GetY() > 3 and self:require_motion_qcf("A") end, }, { "FallEnd", condition = function(self) return self.position.GetY() <= 0.5 end, }, { "Fall", condition = function(self) return self:require_animationfinish() end, }, { "AirHeavyKick", condition = function(self) return self.position.GetY() > 4 and self:require_input("D") end, }, @@ -938,6 +957,7 @@ local function Character(face, shirt_color) Fall = { { "StaggerAirStart", condition = function(self) return self:require_hurt() and self.position.GetY() > 0 end, }, { "StaggerStart", condition = function(self) return self:require_hurt() end, }, + { "Fireball", condition = function(self) return not self.fireball_active and self.position.GetY() > 3 and self:require_motion_qcf("A") end, }, { "Jump", condition = function(self) return self.jumps_remaining > 0 and self:require_input_window("58", 7) end, }, { "JumpBack", condition = function(self) return self.jumps_remaining > 0 and self:require_input_window("57", 7) end, }, { "JumpForward", condition = function(self) return self.jumps_remaining > 0 and self:require_input_window("59", 7) end, }, @@ -1037,7 +1057,7 @@ local function Character(face, shirt_color) }, Fireball = { { "StaggerStart", condition = function(self) return self:require_hurt() end, }, - { "Idle", condition = function(self) return self:require_animationfinish() end, }, + { "Idle", condition = function(self) return self:require_frame(32) end, }, }, StaggerStart = { @@ -1213,6 +1233,13 @@ local function Character(face, shirt_color) effect_scene.Component_GetEmitter(self.effect_spark).SetEmitCount(0) -- don't emit continuously scene.Merge(effect_scene) + effect_scene.Clear() + self.model_fireball = LoadModel(effect_scene, "../models/emitter_fireball.wiscene") + self.effect_fireball = effect_scene.Entity_FindByName("fireball") -- query the emitter entity by name + effect_scene.Component_GetEmitter(self.effect_fireball).SetEmitCount(0) -- don't emit continuously + effect_scene.Component_GetTransform(self.model_fireball).Translate(Vector(0,0,-1000000)) + scene.Merge(effect_scene) + -- HP bar, etc. sprites: @@ -1475,6 +1502,8 @@ local function Character(face, shirt_color) fx.SetSize(vector.Multiply(Vector(360, 180), scaling)) self.sprite_timer.SetParams(fx) end + + signal("subprocess_update" .. self.model) end, @@ -1483,6 +1512,13 @@ local function Character(face, shirt_color) -- apply velocity: self.position = vector.Add(self.position, vector.Multiply(self.velocity, ccd_step)) + + -- Compute global transform for the model: + local model_transform = scene.Component_GetTransform(self.model) + model_transform.ClearTransform() + model_transform.Translate(self.position) + model_transform.Rotate(Vector(0, math.pi * ((self.face - 1) * 0.5))) + model_transform.UpdateTransform() -- Reset collision boxes: self.clipbox = AABB() @@ -1497,35 +1533,18 @@ local function Character(face, shirt_color) current_state.update_collision(self) end if(current_state.clipbox ~= nil) then - self.clipbox = current_state.clipbox + self.clipbox = current_state.clipbox.Transform(model_transform.GetMatrix()) end if(current_state.hurtbox ~= nil) then - table.insert(self.hurtboxes, current_state.hurtbox) + self:set_box_local(self.hurtboxes, current_state.hurtbox) end if(current_state.guardbox ~= nil) then - table.insert(self.guardboxes, current_state.guardbox) + self:set_box_local(self.guardboxes, current_state.guardbox) end end - - -- Compute global transform for the model: - local model_transform = scene.Component_GetTransform(self.model) - model_transform.ClearTransform() - model_transform.Translate(self.position) - model_transform.Rotate(Vector(0, math.pi * ((self.face - 1) * 0.5))) - model_transform.UpdateTransform() - -- Update collision boxes with global model transform: - local model_mat = model_transform.GetMatrix() - self.clipbox = self.clipbox.Transform(model_mat) - for i,hitbox in ipairs(self.hitboxes) do - self.hitboxes[i] = hitbox.Transform(model_mat) - end - for i,hurtbox in ipairs(self.hurtboxes) do - self.hurtboxes[i] = hurtbox.Transform(model_mat) - end - for i,guardbox in ipairs(self.guardboxes) do - self.guardboxes[i] = guardbox.Transform(model_mat) - end + signal("subprocess_update_collisions" .. self.model) + end, -- Draws the hitboxes, etc. @@ -1778,7 +1797,7 @@ runProcess(function() help_text = help_text .. "\nK: player2 will always attack" help_text = help_text .. "\nI: player2 will be idle" help_text = help_text .. "\nH: toggle Debug Draw" - help_text = help_text .. "\n\nMovelist:" + help_text = help_text .. "\n\nMovelist (using numpad notation):" help_text = help_text .. "\n\t A : Light Punch" help_text = help_text .. "\n\t B : Heavy Punch" help_text = help_text .. "\n\t C : Light Kick" @@ -1792,7 +1811,7 @@ runProcess(function() help_text = help_text .. "\n\t 2C : Air Heavy Kick (while jumping)" help_text = help_text .. "\n\t 623B: Shoryuken" help_text = help_text .. "\n\t 236B: Jaunt" - help_text = help_text .. "\n\t 236A: Fireball" + help_text = help_text .. "\n\t 236A: Fireball (also in mid-air)" local font = Font(help_text); font.SetSize(22) font.SetPos(Vector(10, GetScreenHeight() - 10))