master
a327ex 2021-03-24 02:57:26 -03:00
parent bafd765ab3
commit 59a62a2ece
29 changed files with 224 additions and 117 deletions

View File

@ -12,6 +12,7 @@ function Arena:on_enter(from, level, units)
self.hfx:add('condition2', 1) self.hfx:add('condition2', 1)
self.level = level or 1 self.level = level or 1
self.units = units self.units = units
self.logo = true
self.floor = Group() self.floor = Group()
self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'}) self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
@ -59,14 +60,21 @@ function Arena:on_enter(from, level, units)
for i, unit in ipairs(units) do for i, unit in ipairs(units) do
if i == 1 then if i == 1 then
self.player = Player{group = self.main, x = gw/2, y = gh/2, leader = true, character = unit.character, level = unit.level} self.player = Player{group = self.main, x = gw/2, y = gh/2 + 16, leader = true, character = unit.character, level = unit.level}
else else
self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level}) self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level})
end end
end end
if self.level == 1000 then
self.level_1000_text = Text2{group = self.ui, x = gw/2, y = gh/2, lines = {{text = '[fg, wavy_mid]SNKRX', font = fat_font, alignment = 'center'}}}
-- self.level_1000_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 64, lines = {{text = '[fg, wavy_mid]SNKRX', font = pixul_font, alignment = 'center'}}}
-- Wall{group = self.main, vertices = math.to_rectangle_vertices(gw/2 - 0.45*self.level_1000_text.w, gh/2 - 0.3*self.level_1000_text.h, gw/2 + 0.45*self.level_1000_text.w, gh/2 - 3), snkrx = true, color = bg[-1]}
else
-- Set win condition and enemy spawns -- Set win condition and enemy spawns
self.win_condition = random:table{'time', 'enemy_kill', 'wave'} self.win_condition = random:table{'time', 'enemy_kill', 'wave'}
if self.level == 18 and self.trailer then self.win_condition = 'wave' end
if self.win_condition == 'wave' then if self.win_condition == 'wave' then
self.level_to_max_waves = { self.level_to_max_waves = {
1, 2, random:int(2, 3), 1, 2, random:int(2, 3),
@ -169,6 +177,13 @@ function Arena:on_enter(from, level, units)
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 and self.time_left <= 0 end, function() self.can_quit = true end) self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 and self.time_left <= 0 end, function() self.can_quit = true end)
end end
if self.level == 18 and self.trailer then
Text2{group = self.ui, x = gw/2, y = gh/2 - 24, lines = {{text = '[fg, wavy]SNKRX', font = fat_font, alignment = 'center'}}}
Text2{group = self.ui, x = gw/2, y = gh/2, sx = 0.5, sy = 0.5, lines = {{text = '[fg, wavy_mid]try the demo & wishlist!', font = fat_font, alignment = 'center'}}}
Text2{group = self.ui, x = gw/2, y = gh/2 + 24, sx = 0.5, sy = 0.5, lines = {{text = '[light_bg, wavy_mid]music: kubbi - ember', font = fat_font, alignment = 'center'}}}
end
end
if self.level == 1 then if self.level == 1 then
local t1 = Text2{group = self.floor, x = gw/2, y = gh/2 + 2, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]<- or a -> or d', font = fat_font, alignment = 'center'}}} local t1 = Text2{group = self.floor, x = gw/2, y = gh/2 + 2, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]<- or a -> or d', font = fat_font, alignment = 'center'}}}
local t2 = Text2{group = self.floor, x = gw/2, y = gh/2 + 18, lines = {{text = '[light_bg]turn left turn right', font = pixul_font, alignment = 'center'}}} local t2 = Text2{group = self.floor, x = gw/2, y = gh/2 + 18, lines = {{text = '[light_bg]turn left turn right', font = pixul_font, alignment = 'center'}}}
@ -298,7 +313,7 @@ function Arena:update(dt)
end end
self:update_game_object(dt*slow_amount) self:update_game_object(dt*slow_amount)
cascade_instance.pitch = math.clamp(slow_amount*self.main_slow_amount, 0.05, 1) -- cascade_instance.pitch = math.clamp(slow_amount*self.main_slow_amount, 0.05, 1)
if input.k.pressed then if input.k.pressed then
local enemies = self.main:get_objects_by_classes(self.enemies) local enemies = self.main:get_objects_by_classes(self.enemies)
@ -383,6 +398,7 @@ function Arena:draw()
self.main:draw() self.main:draw()
self.post_main:draw() self.post_main:draw()
self.effects:draw() self.effects:draw()
if self.level == 18 and self.trailer then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end
self.ui:draw() self.ui:draw()
camera:attach() camera:attach()

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

View File

@ -170,9 +170,9 @@ function BuyScreen:set_party_and_sets()
local classes = get_classes(self.units) local classes = get_classes(self.units)
for i, class in ipairs(classes) do for i, class in ipairs(classes) do
local x, y local x, y
if #classes <= 8 then x, y = math.index_to_coordinates(i, 2) if #classes <= 6 then x, y = math.index_to_coordinates(i, 2)
else x, y = math.index_to_coordinates(i, 3) end else x, y = math.index_to_coordinates(i, 3) end
table.insert(self.sets, ClassIcon{group = self.main, x = (#classes <= 8 and 319 or 308) + (x-1)*20, y = 45 + (y-1)*56, class = class, units = self.units, parent = self}) table.insert(self.sets, ClassIcon{group = self.main, x = (#classes <= 6 and 319 or 308) + (x-1)*20, y = 45 + (y-1)*56, class = class, units = self.units, parent = self})
end end
end end
@ -319,6 +319,19 @@ function RerollButton:update(dt)
self:update_game_object(dt) self:update_game_object(dt)
if self.selected and input.m1.pressed then if self.selected and input.m1.pressed then
if gold < 2 then
self.spring:pull(0.2, 200, 10)
self.selected = true
error1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
if not self.info_text then
self.info_text = InfoText{group = main.current.ui}
self.info_text:activate({
{text = '[fg]not enough gold', font = pixul_font, alignment = 'center'},
}, nil, nil, nil, nil, 16, 4, nil, 2)
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
end
self.t:after(2, function() self.info_text:deactivate(); self.info_text.dead = true; self.info_text = nil end, 'info_text')
else
ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.parent:set_cards(random:int(1, 25), true) self.parent:set_cards(random:int(1, 25), true)
self.selected = true self.selected = true
@ -326,6 +339,7 @@ function RerollButton:update(dt)
gold = gold - 2 gold = gold - 2
self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}}
end end
end
end end

View File

@ -413,3 +413,24 @@ Mostly done with balance tuning. Now all that's left are some final details:
The demo is finally 100% complete. Now tomorrow I'll spend some time recording gameplay and hopefully finishing the trailer. After that I can start working on the steam page. The demo is finally 100% complete. Now tomorrow I'll spend some time recording gameplay and hopefully finishing the trailer. After that I can start working on the steam page.
If I have it done by tomorrow and Valve takes 5 business days to approve the store page I should have everything ready by the 25th. And then I can release the game 14 days after that, which would be the 8th of April. If I have it done by tomorrow and Valve takes 5 business days to approve the store page I should have everything ready by the 25th. And then I can release the game 14 days after that, which would be the 8th of April.
I definitely want to release it around that time, before the 15th because then I will have completed the game in less than 60 days which is my limit, although I should probably aim for 40 days going forward. I definitely want to release it around that time, before the 15th because then I will have completed the game in less than 60 days which is my limit, although I should probably aim for 40 days going forward.
# Week 5 - 17/03/21 to 24/03/21
This latest week I did everything necessary to get the game into a playable state as well as all the work needed for a Steam page. Most of it was spent making the trailer, but I feel like the more trailers I make
the faster I get at making them. This time it took like 3-4 days out of laziness, but I can easily see it being a 1 day job in the future.
I also tested the demo out with a few people and the results were underwhelming. No one seemed to play it for too much time, which I suspected would happen given that the longer term loop of the game isn't in yet.
More interestingly though, all of the feedback I was given about things that needed to be changed were things that I knew needed to be changed/added for the game's release, which means that I have a pretty good idea of where
the game is from other people's perspective.
The web build has a few bugs that I can't fix like sound effects not playing randomly, and since my strategy was doing a web demo coupled with the page's release, I've decided to change it. Both because of these bugs and the
underwhelming response I feel like releasing a demo at this point will damage the game more than help it. I have ~3 weeks until release date (13th of April) from now, and that should be enough to add enough things into the game
to make it significantly better.
Going forward I think the Steam page reveal demo strategy probably isn't a good idea for these 1 month games. They're small enough already as they are and releasing them in an ever more crude state is probably a waste of time.
The only thing I need to schedule better for next releases is my trailer making timing. If I want to release a game in 1 month I need to have a trailer by day 15 at the latest, which means I need to work on the game for 2 weeks
and then take 1 day to make a trailer.
As for feedback given from the demo:

View File

@ -58,8 +58,8 @@ function Seeker:on_collision_enter(other, contact)
elseif table.any(main.current.enemies, function(v) return other:is(v) end) then elseif table.any(main.current.enemies, function(v) return other:is(v) end) then
if self.being_pushed and math.length(self:get_velocity()) > 60 then if self.being_pushed and math.length(self:get_velocity()) > 60 then
other:hit(math.floor(self.dmg/2)) other:hit(math.floor(self.dmg/4))
self:hit(self.dmg) self:hit(math.floor(self.dmg/2))
other:push(random:float(10, 15), other:angle_to_object(self)) other:push(random:float(10, 15), other:angle_to_object(self))
HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1} HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end

View File

@ -1,4 +1,4 @@
call "C:\Program Files\7-Zip\7z.exe" a -r %1.zip -w ..\..\ -xr!engine/love -xr!builds -xr!.git -xr!*.moon call "C:\Program Files\7-Zip\7z.exe" a -r %1.zip -w ..\..\ -xr!engine/love -xr!builds -xr!.git -xr!*.moon
rename %1.zip %1.love rename %1.zip %1.love
call love-js -c -m 268435456 -t %1 %2\engine\love\%1.love ..\..\builds\web call love-js -c -m 1073741824 -t %1 %2\engine\love\%1.love ..\..\builds\web
del %1.love del %1.love

View File

@ -1,3 +1,4 @@
web = true
require 'engine' require 'engine'
require 'shared' require 'shared'
require 'arena' require 'arena'
@ -423,7 +424,6 @@ function update(dt)
end end
if input.m.pressed then if input.m.pressed then
print(music.volume)
if music.volume == 0.5 then if music.volume == 0.5 then
music.volume = 0 music.volume = 0
elseif music.volume == 0 then elseif music.volume == 0 then
@ -443,7 +443,7 @@ end
function love.run() function love.run()
return engine_run({ return engine_run({
game_name = 'SNAKRX', game_name = 'SNAKRX',
window_width = 480*3, window_width = 480*2,
window_height = 270*3, window_height = 270*2,
}) })
end end

View File

@ -469,6 +469,9 @@ function Player:on_collision_enter(other, contact)
if other:is(Wall) then if other:is(Wall) then
if self.leader then if self.leader then
if other.snkrx then
main.current.level_1000_text:pull(0.2, 200, 10)
end
self.hfx:use('hit', 0.5, 200, 10, 0.1) self.hfx:use('hit', 0.5, 200, 10, 0.1)
camera:spring_shake(2, math.pi - self.r) camera:spring_shake(2, math.pi - self.r)
self:bounce(contact:getNormal()) self:bounce(contact:getNormal())

2
run.sh
View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
cd E:/a327ex/SNAKRX # change to the directory of the current project cd E:/a327ex/SNKRX # change to the directory of the current project
engine/love/love.exe --console . engine/love/love.exe --console .

View File

@ -14,7 +14,7 @@ function shared_init()
purple = ColorRamp(Color'#8e559e', 0.025), purple = ColorRamp(Color'#8e559e', 0.025),
} }
for name, color in pairs(colors) do _G[name] = color end for name, color in pairs(colors) do _G[name] = color end
modal_transparent = Color(0.1, 0.1, 0.1, 0.5) modal_transparent = Color(0.1, 0.1, 0.1, 0.6)
fg_transparent = Color(fg[0].r, fg[0].g, fg[0].b, 0.5) fg_transparent = Color(fg[0].r, fg[0].g, fg[0].b, 0.5)
graphics.set_background_color(bg[0]) graphics.set_background_color(bg[0])
@ -433,6 +433,7 @@ global_text_tags = {
light_bg = TextTag{draw = function(c, i, text) graphics.set_color(bg[5]) end}, light_bg = TextTag{draw = function(c, i, text) graphics.set_color(bg[5]) end},
fg = TextTag{draw = function(c, i, text) graphics.set_color(fg[0]) end}, fg = TextTag{draw = function(c, i, text) graphics.set_color(fg[0]) end},
fgm5 = TextTag{draw = function(c, i, text) graphics.set_color(fg[-5]) end}, fgm5 = TextTag{draw = function(c, i, text) graphics.set_color(fg[-5]) end},
fgm10 = TextTag{draw = function(c, i, text) graphics.set_color(fg[-10]) end},
wavy = TextTag{update = function(c, dt, i, text) c.oy = 2*math.sin(4*time + i) end}, wavy = TextTag{update = function(c, dt, i, text) c.oy = 2*math.sin(4*time + i) end},
wavy_mid = TextTag{update = function(c, dt, i, text) c.oy = 0.75*math.sin(3*time + i) end}, wavy_mid = TextTag{update = function(c, dt, i, text) c.oy = 0.75*math.sin(3*time + i) end},
wavy_mid2 = TextTag{update = function(c, dt, i, text) c.oy = 0.5*math.sin(3*time + i) end}, wavy_mid2 = TextTag{update = function(c, dt, i, text) c.oy = 0.5*math.sin(3*time + i) end},
@ -474,6 +475,7 @@ Text2:implement(GameObject)
function Text2:init(args) function Text2:init(args)
self:init_game_object(args) self:init_game_object(args)
self.text = Text(args.lines, global_text_tags) self.text = Text(args.lines, global_text_tags)
self.w, self.h = self.text.w, self.text.h
end end
@ -484,7 +486,14 @@ end
function Text2:draw() function Text2:draw()
self.text:draw(self.x, self.y, self.r, self.sx, self.sy) self.text:draw(self.x, self.y, self.r, self.spring.x*self.sx, self.spring.x*self.sy)
end
function Text2:pull(...)
self.spring:pull(...)
self.r = random:table{-math.pi/24, math.pi/24}
self.t:tween(0.2, self, {r = 0}, math.linear)
end end

44
todo
View File

@ -1,3 +1,40 @@
Trailer:
1
01:31
03:37
05:45
06:44
07:50
14:07
2
01:01
05:21
08:02
10:40
11:55
27:00 wall bump
27:17
3
00:23
12:12
4
02:30
5
01:00
03:36
07:07
6
00:14
03:45
04:29
06:19
09:40
10:27
12:51
13:51
15:12 fast buy
Mini Boss every 3rd level Mini Boss every 3rd level
Show a unit DPS list like Underlord's to the right side of the screen Show a unit DPS list like Underlord's to the right side of the screen
About 20-30 passive items that can be collected every 3 levels About 20-30 passive items that can be collected every 3 levels
@ -42,3 +79,10 @@ Bugs
Sage's pull force doesn't increase with unit level Sage's pull force doesn't increase with unit level
Cleric's healing amount doesn't increase with unit level Cleric's healing amount doesn't increase with unit level
Squire and Chronomancer's buffs don't increase with unit level Squire and Chronomancer's buffs don't increase with unit level
Engine improvements for after SNKRX release
on_hit:
on_collision_enter/exit are automatically called and automatically call on_hit/on_leave for each object
This enables the definition of on_hit on each object and the question of where the logic should stay is solved/dodged
Spurred by Wall needing to have its own on_hit function to do something when the player hits it, without having to change player code for all Walls,
Defining on_hit on the Wall creation call for that specific Wall, and thus that specific Wall will have this behavior while other walls won't