diff options
33 files changed, 541 insertions, 191 deletions
@@ -1,6 +1,8 @@ Art - opengameart.org user Buch - ui sprites (CC-BY) opengameart.org user Yughues - textures (CC0) +opengameart.org user Admurin - ui sprites (GPL3) +opengameart.org user JStatz - textures (CC0) Software - Matthias Richter (github.com user vrld) - hc.lua (MIT) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e07d473 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ + +# Night fishing + +A short game made for global game jam 2025 +Go fishing by lamplight, look for disturbences in the water +WASD + left click diff --git a/data_src/world/bobber_normal.png b/data_src/world/bobber_normal.png Binary files differnew file mode 100644 index 0000000..6123392 --- /dev/null +++ b/data_src/world/bobber_normal.png diff --git a/data_src/world/fish_normal.png b/data_src/world/fish_normal.png Binary files differnew file mode 100644 index 0000000..4cd2988 --- /dev/null +++ b/data_src/world/fish_normal.png diff --git a/data_src/world/floor_normal.png b/data_src/world/floor_normal.png Binary files differindex a8b1499..ca403e4 100644 --- a/data_src/world/floor_normal.png +++ b/data_src/world/floor_normal.png diff --git a/data_src/world/help_1.png b/data_src/world/help_1.png Binary files differnew file mode 100644 index 0000000..82bf2dd --- /dev/null +++ b/data_src/world/help_1.png diff --git a/data_src/world/help_2.png b/data_src/world/help_2.png Binary files differnew file mode 100644 index 0000000..5395017 --- /dev/null +++ b/data_src/world/help_2.png diff --git a/data_src/world/help_3.png b/data_src/world/help_3.png Binary files differnew file mode 100644 index 0000000..1772e8e --- /dev/null +++ b/data_src/world/help_3.png diff --git a/data_src/world/player_normal.png b/data_src/world/player_normal.png Binary files differindex 3d8d384..e1611a7 100644 --- a/data_src/world/player_normal.png +++ b/data_src/world/player_normal.png diff --git a/data_src/world/rocks_normal.png b/data_src/world/rocks_normal.png Binary files differindex b03e87c..6d25ad5 100644 --- a/data_src/world/rocks_normal.png +++ b/data_src/world/rocks_normal.png diff --git a/data_src/world/sea_normal.png b/data_src/world/sea_normal.png Binary files differindex 8298bf6..a8abdda 100644 --- a/data_src/world/sea_normal.png +++ b/data_src/world/sea_normal.png diff --git a/data_src/world/wall_inside_normal.png b/data_src/world/wall_inside_normal.png Binary files differindex 8d38da3..6a8b1a0 100644 --- a/data_src/world/wall_inside_normal.png +++ b/data_src/world/wall_inside_normal.png diff --git a/data_src/world/wall_outside_normal.png b/data_src/world/wall_outside_normal.png Binary files differindex 097bfc1..0b47790 100644 --- a/data_src/world/wall_outside_normal.png +++ b/data_src/world/wall_outside_normal.png diff --git a/src/bobber.moon b/src/bobber.moon index 6f52c6b..cee0f14 100644 --- a/src/bobber.moon +++ b/src/bobber.moon @@ -1,6 +1,8 @@ world = require("world") sprites = require("world.sprites") ecs = require("ecs") +win = require("window") +colors = require("color") class BobberGraphicsComponent extends world.GraphicsComponent @loctbl = { @@ -16,7 +18,7 @@ class BobberGraphicsComponent extends world.GraphicsComponent populate_buf: (geom_view, normal_view, offset) => @buf = geom_view h = 0.1 - uv = sprites.player_normal + uv = sprites.bobber_normal utbl = { [-1]: {uv.s1, uv.t1} [1]: {uv.s2, uv.t2} @@ -27,6 +29,22 @@ class BobberGraphicsComponent extends world.GraphicsComponent loctbl = @@loctbl[i] geom_view[i] = vec3(@@loctbl[i][1] * h, @@loctbl[i][2] * h, z) + vec3(@properties.pos.x, @properties.pos.y, z) normal_view[i] = vec2(utbl[@@loctbl[i][1]][1], utbl[@@loctbl[i][2]][2]) + join: (entity) => + super(entity) + aspect = win.width / win.height + program = @.node("use_program") + graphic = entity\get("bobber") + @node\remove(program) + @node\append(am.blend("alpha")\append(program)) + bind = @.node("bind") + [[ + for name, color in pairs(colors.am_lake_color) + bind[name] = color + ]] + bind.water = 1 + @ent = entity + @last_bubble = am.current_time! + comp = @ class BobberPhysicsComponent extends world.PhysicsComponent new: (name, properties, shape, args) => @@ -55,24 +73,5 @@ class Bobber extends ecs.Entity return false -class BubblesGraphicsComponent extends world.GraphicsComponent - buf_size: () => - 6 - populate_buf: (geom_view, normal_view, offset) => - h = 1 - geom_view[1] = vec3(-h,-h,1) - geom_view[2] = vec3(-h,h,1) - geom_view[3] = vec3(-h,-h,1) - geom_view[4] = vec3(h,h,1) - geom_view[5] = vec3(h,-h,1) - geom_view[6] = vec3(-h,-h,1) - uv = sprites.player_normal - normal_view[1] = vec2(uv.s1,uv.t1) - normal_view[2] = vec2(uv.s1,uv.t2) - normal_view[3] = vec2(uv.s2,uv.t2) - normal_view[4] = vec2(uv.s2,uv.t2) - normal_view[5] = vec2(uv.s2,uv.t1) - normal_view[6] = vec2(uv.s1,uv.t1) - bind = @.node("bind") {:BobberGraphicsComponent, :BobberPhysicsComponent, :Bobber} diff --git a/src/controllers/fish.moon b/src/controllers/fish.moon index 1516574..3c829f3 100644 --- a/src/controllers/fish.moon +++ b/src/controllers/fish.moon @@ -2,12 +2,16 @@ ecs = require("ecs") world = require("world") controller = {} + + + class FishControllerComponent extends ecs.Component new: () => print("Fish controller started") @node = am.group! join: (entity) => super(entity) + @ent = entity graphic = entity\get("graphic") assert(graphic, "Fish controller must have a graphic") pred_component = entity\get("pred") @@ -27,7 +31,7 @@ class FishControllerComponent extends ecs.Component while comp.state == "swimming" comp.state = "waiting" start_wait = world.sync_time! - while world.sync_time! - start_wait < 4 + while world.sync_time! - start_wait < 8 --TODO: look for nearby hooks and get caught coroutine.yield! if comp.state == "waiting" @@ -41,12 +45,33 @@ class FishControllerComponent extends ecs.Component pick_next_location: () => -- Pick somewhere to swim based on where we are? -- This can only be done on the host. + --TODO: spawn fish on all sides. + -- everything has to be floats so math.random returns a float. if @net.properties.pos.x > 10 -- pick somewhere to the right @net.properties.next_loc = vec2( - math.random(10.3,12), - math.random(-10,10) + math.random(11.1,15), + math.random(-10.1,10) + ) + elseif @net.properties.pos.x < -10 + @net.properties.next_loc = vec2( + math.random(-15.1,-11) + math.random(-10.1,10) ) - @net.properties.next_loc_time = world.sync_time! + elseif @net.properties.pos.y > 10 + @net.properties.next_loc = vec2( + math.random(-10.1,10) + math.random(11.1,15) + ) + elseif @net.properties.pos.y < -10 + @net.properties.next_loc = vec2( + math.random(-10.1,10) + math.random(-15.1,-11) + ) + else + --If none of these apply, we're stuck on land somehow, delete ourselves + @entity\destroy! + + @net.properties.next_loc_time = world.sync_time! --@net.properties.next_loc = @net.properties.pos + vec2(0,1) --@net.properties.next_loc_time = world.sync_time! print("Picking next location, it was ", @net.properties.next_loc) diff --git a/src/controllers/mouse_keyboard.moon b/src/controllers/mouse_keyboard.moon index 28c4f58..cc33a72 100644 --- a/src/controllers/mouse_keyboard.moon +++ b/src/controllers/mouse_keyboard.moon @@ -5,6 +5,7 @@ fish = require("spawn_fish") rng = require("rng") us = require("ui.sprites") ui = require("ui") +minigame = require("minigame") assert(fish.Fish, "Failed to find fish from spawn_fish") controller = {} @@ -68,6 +69,7 @@ class MouseKeyboardControllerComponent extends ecs.Component f = ent.bobber.which f.state = "catching" comp\start_minigame(f) + -- TODO: make net destory the fish, not the controller f\destroy! elseif net_component.properties.reeling > 0 print("Reeling in fish!") @@ -88,87 +90,9 @@ class MouseKeyboardControllerComponent extends ecs.Component ) start_minigame: (fish) => @minigame_started = true - node = am.group! - hook_location = 0 -- 0 -> 1? - hook_width = 5 - hook_gravity = 5 -- how quickly do we fall - hook_force = 80 -- how quickly do we accelerate - hook_vel = 0 - hook_length = 1 - hook_bounce_damp = 0.2 --how elastic is the bottom and top? - fish_width = fish.width - fish_force = 100 - fish_gravity = 0 - fish_activity = 0.1 - fish_vel = 0 - fish_bounce_damp = 1 -- perfectly elsastic bounce - reel_progress = 0 - escape_progress = 0 - reel_speed = 0.1 - escape_speed = 0.01 - reel_cutoff = 10 - escape_cutoff = 10 - fish_location = math.random(-256,256) - bar_sprite = require("ui.button")(40,-256,64,512,"").node - node\append(bar_sprite) - hook_sprite = am.translate(0,0)\append(am.scale(1)\append(am.sprite(us.hook))) - node\append(hook_sprite) - fish_g_sprite = am.sprite(us.fish_purple) - fish_b_sprite = am.sprite(us.fish_blue) - fish_sprite = am.translate(0,0)\append(am.scale(1)\append(am.group(fish_g_sprite, fish_b_sprite))) - node\append(fish_sprite) - ui.node\append(node) - net = @net - bobber = @bobber - assert(bobber, "Failed to find bobber") - node\action(() => - if win\mouse_pressed("left") - hook_vel += hook_force - else - hook_vel -= hook_gravity - hook_location += hook_vel * am.delta_time - if hook_location < -256 + 16 -- bounce - hook_vel = -hook_vel * hook_bounce_damp - hook_location = -256 + 16 - elseif hook_location > 256 - 16 - hook_vel = -hook_vel * hook_bounce_damp - hook_location = 256 - 16 - if math.random! < fish_activity - fish_vel = fish_force * math.random(-1,1) - fish_location += fish_vel * am.delta_time - if fish_location < -256 + 16 -- bounce - fish_vel = -fish_vel * fish_bounce_damp - fish_location = -256 + 16 - elseif fish_location > 256 - 16 - fish_vel = -fish_vel * fish_bounce_damp - fish_location = 256 - 16 - - if hook_location - hook_width > fish_location - fish_width and hook_location + hook_width < fish_location + fish_width - fish_b_sprite.hidden = true - fish_g_sprite.hidden = false - reel_progress += reel_speed - else - escape_progress += escape_speed - fish_g_sprite.hidden = true - fish_b_sprite.hidden = false - if reel_progress > reel_cutoff - net.properties.fish_caught += 1 - net.properties.casted = false - net.properties.reeling = 0 - ui.node\remove(node) - bobber.which = nil - elseif escape_progress > escape_cutoff - net.properties.casted = false - net.properties.reeling = 0 - ui.node\remove(node) - bobber.which = nil - --print("reel:", reel_progress, "escape:", escape_progress) - -- Updates all sprites at the end? - hook_sprite("translate").y = hook_location - fish_sprite("translate").y = fish_location - - ) - --error("Starting fishing minigame") + pull = () -> + win\mouse_pressed("left") + minigame.run(@net, @bobber, fish, pull) controller.text_size = 1 controller.Controller = MouseKeyboardControllerComponent diff --git a/src/islandgen.moon b/src/islandgen.moon index 1fdd3eb..1e5b83d 100644 --- a/src/islandgen.moon +++ b/src/islandgen.moon @@ -82,23 +82,45 @@ class IslandGraphicsComponent extends world.GraphicsComponent --bind.lamp1 = vec4(world.world_x + (0.5 * 4 * aspect) - 0.3, world.world_y + (0.5 * 4 * (aspect_inv)) + 0.7, 0, 2.2) --no idea why these magic numbers --bind.lamp2 = vec4(0,0,0,3) buf_size: () => - 6 + squares = 16 + triangles_per_square = 2 + vertexes_per_triangle = 3 + floats_per_vertex = 3 + squares * triangles_per_square * vertexes_per_triangle + --6 populate_buf: (geom_view, normal_view, offset) => z = 0 size = 10 - --@lamp = world.level.add_lamp(vec4(0,0,0,3)) - geom_view[1] = vec3(-size,-size,z) - geom_view[2] = vec3(-size,size,z) - geom_view[3] = vec3(size,size,z) - geom_view[4] = vec3(size,size,z) - geom_view[5] = vec3(size,-size,z) - geom_view[6] = vec3(-size,-size,z) - normal_view[1] = vec2(sprites.rocks_normal.s1, sprites.rocks_normal.t1) - normal_view[2] = vec2(sprites.rocks_normal.s1, sprites.rocks_normal.t2) - normal_view[3] = vec2(sprites.rocks_normal.s2, sprites.rocks_normal.t2) - normal_view[4] = vec2(sprites.rocks_normal.s2, sprites.rocks_normal.t2) - normal_view[5] = vec2(sprites.rocks_normal.s2, sprites.rocks_normal.t1) - normal_view[6] = vec2(sprites.rocks_normal.s1, sprites.rocks_normal.t1) + --@lamp = world.level.add_lamp(vec4(0,0,10,2)) + fuv = sprites.rocks_normal + floor = (geom, uv, offset, start, finish) -> + geom[offset + 0] = vec3(start.x,start.y,z) + geom[offset + 1] = vec3(start.x,finish.y,z) + geom[offset + 2] = vec3(finish.x,finish.y,z) + geom[offset + 3] = vec3(finish.x,finish.y,z) + geom[offset + 4] = vec3(finish.x,start.y,z) + geom[offset + 5] = vec3(start.x,start.y,z) + normal_view[offset + 0] = vec2(fuv.s1, fuv.t1) + normal_view[offset + 1] = vec2(fuv.s1, fuv.t2) + normal_view[offset + 2] = vec2(fuv.s2, fuv.t2) + normal_view[offset + 3] = vec2(fuv.s2, fuv.t2) + normal_view[offset + 4] = vec2(fuv.s2, fuv.t1) + normal_view[offset + 5] = vec2(fuv.s1, fuv.t1) + x_panels = 4 + y_panels = 4 + x_stride = (size * 2) / x_panels + y_stride = (size * 2) / y_panels + j = 1 + for floorx = 1,x_panels + for floory = 1,y_panels + floor( + geom_view, + normal_view, + j, + vec2(-size + (x_stride*(floorx-1)), -size + (y_stride*(floory-1))), + vec2(-size + (x_stride*floorx), -size + (y_stride*floory)) + ) + j += 6 class WaterGraphicsComponent extends world.GraphicsComponent action: (bind) => @@ -177,7 +199,12 @@ gen.protogen = (seed) -> IslandGraphicsComponent("island") }) ecs.Entity(nil, { - WaterGraphicsComponent("water") + water: WaterGraphicsComponent("water") + spawner1: fish.SpawnFishComponent("spawner",{},vec4(10.3,-10,15,15)) + spawner2: fish.SpawnFishComponent("spawner",{},vec4(-10,10.3,15,15)) + spawner3: fish.SpawnFishComponent("spawner",{},vec4(-15,-15,9.7,10)) + spawner4: fish.SpawnFishComponent("spawner",{},vec4(-15,-15,10,9.7)) }) + --ecs.Entity(nil, { gen diff --git a/src/main.lua b/src/main.lua index 517e3fd..7470724 100644 --- a/src/main.lua +++ b/src/main.lua @@ -28,9 +28,9 @@ win.scene:append(ui.node) local router = require("router") win.scene:append(router.node) -- Needed to pump the net state machine ---input_menu = require("menu.input") ---input_menu.initalize() -require("worldgen") +local menu = require("menu.main") +menu.initalize() +--require("worldgen") --require("world_test") --require("net_test") --require("ui_test") diff --git a/src/menu/main.moon b/src/menu/main.moon index 764ce28..ee33dc9 100644 --- a/src/menu/main.moon +++ b/src/menu/main.moon @@ -12,50 +12,18 @@ buttons_data = { require("menu.settings").initalize! } { - text: "Join" + text: "Start" on: () => menu.destroy! - require("menu.join").initalize! - } - { - text: "Host" - on: () => - print("Setting co...") - if not @node.co - @node.co = coroutine.create(() -> - server = router.Router! - server\initalize! - server - ) - button = @ - @node\action(() => - print("In coroutine, menu is", menu) - if @co and coroutine.status(@co) ~= "dead" - succ, val = coroutine.resume(@co) - if not succ - error(debug.traceback(@co,val)) - if type(val) == "string" - print("Setting text", val) - button.text.text = val - else - print("Returned router") - world.router = val - menu.destroy! - require("menu.playername").initalize(true) - ) - } - { - text: "Tutorial" - on: () => - menu.destroy! - print("Load tutorial level") + require("worldgen") + --require("menu.join").initalize! } } menu.initalize = () -> starty = -200 for i = starty, ((#buttons_data-1) * (64 + 32)) + starty, 64 + 32 print("making button", #buttons + 1) - buttons[#buttons + 1] = ui.button(-100,i,200,64,buttons_data[#buttons + 1].text) + buttons[#buttons + 1] = ui.button(-200,i,400,64,buttons_data[#buttons + 1].text) buttons[#buttons].on = buttons_data[#buttons].on print("intalize") @@ -63,5 +31,6 @@ menu.initalize = () -> menu.destroy = () -> for button in *buttons ui.delete(button) + buttons = {} menu diff --git a/src/menu/settings.moon b/src/menu/settings.moon new file mode 100644 index 0000000..1f21cc3 --- /dev/null +++ b/src/menu/settings.moon @@ -0,0 +1,58 @@ +ui = require("ui") +router = require("router") +world = require("world") +settings = require("settings") +menu = {} + +buttons = {} +buttons_data = { + { + text: "Streamer" + on: (depressed) => + --error("depressed:" .. depressed) + settings.streamer = depressed and 0 or 1 + print("streamer is now:", settings.streamer) + type: "boolean" + } + { + text: "Volume" + on: (e) => + --require("worldgen") + --require("menu.join").initalize! + settings.volume = tonumber(@text.text) + type: "slider" + + } + { + text: "Done" + on: () => + menu.destroy! + require("menu.main").initalize! + type: "button" + } +} +menu.initalize = () -> + starty = -200 + for i = starty, ((#buttons_data-1) * (64 + 32)) + starty, 64 + 32 + button_data = buttons_data[#buttons + 1] + if button_data.type == "boolean" + buttons[#buttons + 1] = ui.checkbox(-200,i,400,64,button_data.text) + buttons[#buttons].on = button_data.on + elseif button_data.type == "slider" + buttons[#buttons + 1] = ui.textbox(-200,i,400,64,settings.volume) + buttons[#buttons].on = button_data.on + elseif button_data.type == "button" + buttons[#buttons + 1] = ui.button(-200,i,400,64,button_data.text) + buttons[#buttons].on = button_data.on + else + error("Unknown button type:" .. button_data.type) + print("making button", #buttons + 1) + + print("intalize") + +menu.destroy = () -> + for button in *buttons + ui.delete(button) + buttons = {} + +menu diff --git a/src/minigame.moon b/src/minigame.moon new file mode 100644 index 0000000..25d567a --- /dev/null +++ b/src/minigame.moon @@ -0,0 +1,139 @@ +ui = require("ui") +us = require("ui.sprites") +settings = require("settings") +win = require("window") +color = require("color") +game = {} + +caught = am.translate(-win.width/2,win.height/2)\append(am.scale(2)\append(am.text("Caught: 0",color.am_color.highlight,"left","top"))) +caught.hidden = true +ui.node\append(caught) + +am.ascii_color_map = { + o: color.am_color.outline + p: color.am_color.foreground + b: color.am_lake_color.foreground +} + +bar_sprite = (char, w, h) -> + sprite = {} + sprite[1] = "o"\rep(w) + for i = 2, h - 1 + sprite[i] = char\rep(w) + sprite[h] = "o"\rep(w) + table.concat(sprite,"\n") +bar_y = 276 +catch_bar = am.translate(0,bar_y)\append(am.scale(vec2(0,4))\append(am.sprite( + bar_sprite("p",256,8), nil, "left" +))) +escape_bar = am.translate(0,bar_y)\append(am.scale(vec2(0,4))\append(am.sprite( + bar_sprite("b",256,8), nil, "right" +))) +catch_bar_cutoff = am.translate(256,bar_y)\append(am.scale(vec2(1,4))\append(am.sprite( + bar_sprite("p",1,8), nil, "left" +))) +escape_bar_cutoff = am.translate(-256,bar_y)\append(am.scale(vec2(1,4))\append(am.sprite( + bar_sprite("b",1,8), nil, "right" +))) +game.run = (net, bobber, fish, pull) -> + node = am.group! + hook_location = 0 -- 0 -> 1? + hook_width = 5 + hook_gravity = 5 -- how quickly do we fall + hook_force = 120 -- how quickly do we accelerate + hook_vel = 0 + hook_length = 1 + hook_bounce_damp = 0.2 --how elastic is the bottom and top? + fish_width = fish.width + fish_force = 100 + fish_gravity = 0 + fish_activity = 0.1 + fish_vel = 0 + fish_bounce_damp = 1 -- perfectly elsastic bounce + reel_progress = 0 + escape_progress = 0 + reel_speed = 0.02 + escape_speed = 0.012 + reel_cutoff = 10 + escape_cutoff = 10 + last_played = am.current_time! + play_delay = 0.1 + fish_location = math.random(-256,256) + bar_sprite = require("ui.button")(40,-256,64,512,"").node + node\append(bar_sprite) + hook_sprite = am.translate(72,0)\append(am.scale(1)\append(am.sprite(us.hook))) + node\append(hook_sprite) + fish_g_sprite = am.sprite(us.fish_purple) + fish_b_sprite = am.sprite(us.fish_blue) + fish_sprite = am.translate(72,0)\append(am.scale(vec2(1,fish_width / fish_g_sprite.height))\append(am.group(fish_g_sprite, fish_b_sprite))) + node\append(fish_sprite) + ui.node\append(node) + assert(bobber, "Failed to find bobber") + node\append(catch_bar) + node\append(escape_bar) + node\append(catch_bar_cutoff) + node\append(escape_bar_cutoff) + caught\action(() => + if net.properties.fish_caught > 0 + @hidden = false + @("text").text = string.format("Caught: %d", net.properties.fish_caught) + ) + node\action(() => + if pull! + hook_vel += hook_force + else + hook_vel -= hook_gravity + hook_location += hook_vel * am.delta_time + if hook_location < -256 + 16 -- bounce + hook_vel = -hook_vel * hook_bounce_damp + hook_location = -256 + 16 + elseif hook_location > 256 - 16 + hook_vel = -hook_vel * hook_bounce_damp + hook_location = 256 - 16 + if math.random! < fish_activity + fish_vel = fish_force * math.random(-1,1) + fish_location += fish_vel * am.delta_time + if fish_location < -256 + 16 -- bounce + fish_vel = -fish_vel * fish_bounce_damp + fish_location = -256 + 16 + elseif fish_location > 256 - 16 + fish_vel = -fish_vel * fish_bounce_damp + fish_location = 256 - 16 + + if hook_location - hook_width > fish_location - fish_width and hook_location + hook_width < fish_location + fish_width + fish_b_sprite.hidden = true + fish_g_sprite.hidden = false + reel_progress += reel_speed + if am.current_time! - last_played > play_delay + @action("sfx",am.play(32044500, false, 1 + (reel_progress/10), settings.volume)) + last_played = am.current_time! + else + escape_progress += escape_speed + fish_g_sprite.hidden = true + fish_b_sprite.hidden = false + if am.current_time! - last_played > play_delay + @action("sfx",am.play(3469004, false, 1 + (escape_progress/10), settings.volume)) + last_played = am.current_time! + catch_bar("scale").x = escape_progress / escape_cutoff + escape_bar("scale").x = reel_progress / reel_cutoff + if reel_progress > reel_cutoff + net.properties.fish_caught += 1 + net.properties.casted = false + net.properties.reeling = 0 + ui.node\remove(node) + bobber.which = nil + @action("sfx",am.play(12507000, false, 1, settings.volume)) + elseif escape_progress > escape_cutoff + net.properties.casted = false + net.properties.reeling = 0 + ui.node\remove(node) + bobber.which = nil + @action("sfx",am.play(9122106, false, 1, settings.volume)) + --print("reel:", reel_progress, "escape:", escape_progress) + -- Updates all sprites at the end? + hook_sprite("translate").y = hook_location + fish_sprite("translate").y = fish_location + ) + + +game diff --git a/src/player.moon b/src/player.moon index da1c8dc..04bb146 100644 --- a/src/player.moon +++ b/src/player.moon @@ -67,7 +67,8 @@ class PlayerLineGraphicComponent extends world.GraphicsComponent direction += math.pi rot = math.rotate4(direction) move2 = vec3(s.pred.properties.pos, 0) - scale = s.pred.properties.cast_end + cast_end = s.pred.properties.cast_end + scale = math.sqrt(cast_end / math.length(offset)) * math.length(offset) z = -0.12 local1 = vec4(-width, 0,z,1) * rot local2 = vec4(-width, scale,z,1) * rot @@ -182,7 +183,7 @@ class PlayerPredictedComponent extends ecs.PredictedComponent new: (name) => super(name, {vel: vec2(0,0), pos:vec2(0,0), accel: vec2(0,0), cast_end: 0, can_reel:false}, "net", { accel:() => - vec2(@net.properties.accel) * (world.level.on_land(@properties.pos) and 1 or 0.5) + vec2(@net.properties.accel) * (world.level.on_land(@properties.pos) and 1 or 0.5) * (@net.properties.drown and 0 or 1) vel: () => --print("Net is ", @net.properties) delta = world.sync_time! - @net.properties.last_update @@ -227,7 +228,7 @@ class PlayerPredictedComponent extends ecs.PredictedComponent if land @node\action("stepsfx", am.play(60861008 + math.random(10) * 100, false, 1, settings.volume)) else - @node\action("stepsfx", am.play(78618302 + math.random(8) * 10, false, 1, settings.volume)) + @node\action("stepsfx", am.play(3444209 + math.random(8) * 10, false, 1, settings.volume)) @last_step = am.current_time! if @properties.cast_end > 0 and @properties.cast_end < 0.1 @node\action("castsfx", am.play(41228309, false, 1, settings.volume)) diff --git a/src/prefab/cabin.moon b/src/prefab/cabin.moon index 915ea92..b56ba1c 100644 --- a/src/prefab/cabin.moon +++ b/src/prefab/cabin.moon @@ -17,6 +17,9 @@ class CabinGraphicsComponent extends world.GraphicsComponent iuv = sprites.wall_inside_normal ouv = sprites.wall_outside_normal fuv = sprites.floor_normal + tutorial_keys = false + tutorial_mouse = false + tutorial_visual = false wall = (geom, uv, offset, start, finish, texture) -> geom[offset + 0] = vec3(start.x, start.y, z1) geom[offset + 1] = vec3(start.x, start.y, z2) @@ -32,22 +35,33 @@ class CabinGraphicsComponent extends world.GraphicsComponent uv[offset+5] = vec2(texture.s1,texture.t1) floor = (geom, uv, offset, start, finish) -> + tuv = fuv + if not tutorial_keys + tuv = sprites.help_1 + tutorial_keys = true + elseif not tutorial_mouse + tuv = sprites.help_2 + tutorial_mouse = true + elseif not tutorial_visual + tuv = sprites.help_3 + tutorial_visual = true geom[offset + 0] = vec3(start.x,start.y,z1) geom[offset + 1] = vec3(start.x,finish.y,z1) geom[offset + 2] = vec3(finish.x,finish.y,z1) geom[offset + 3] = vec3(finish.x,finish.y,z1) geom[offset + 4] = vec3(finish.x,start.y,z1) geom[offset + 5] = vec3(start.x,start.y,z1) - normal_view[offset + 0] = vec2(fuv.s1, fuv.t1) - normal_view[offset + 1] = vec2(fuv.s1, fuv.t2) - normal_view[offset + 2] = vec2(fuv.s2, fuv.t2) - normal_view[offset + 3] = vec2(fuv.s2, fuv.t2) - normal_view[offset + 4] = vec2(fuv.s2, fuv.t1) - normal_view[offset + 5] = vec2(fuv.s1, fuv.t1) + normal_view[offset + 0] = vec2(tuv.s1, tuv.t1) + normal_view[offset + 1] = vec2(tuv.s1, tuv.t2) + normal_view[offset + 2] = vec2(tuv.s2, tuv.t2) + normal_view[offset + 3] = vec2(tuv.s2, tuv.t2) + normal_view[offset + 4] = vec2(tuv.s2, tuv.t1) + normal_view[offset + 5] = vec2(tuv.s1, tuv.t1) --left wall j = 1 - wall(geom_view, normal_view, j, vec2(-2,-2),vec2(-2,0), sprites.wall_inside_normal) + --wall(geom_view, normal_view, j, vec2(-2,-2),vec2(-2,0), sprites.wall_inside_normal) + --lamp = world.level.add_lamp(vec4(0,0,1,2)) j += 6 for floorx = 1,3 for floory = 1,3 diff --git a/src/settings.moon b/src/settings.moon index 0cd1d76..5db1401 100644 --- a/src/settings.moon +++ b/src/settings.moon @@ -3,7 +3,7 @@ settings = {} -- Passed to the land shader to add noise to lamps -settings.streamer = 0 +settings.streamer = 1 -- Volume for sound effects settings.volume = 1 diff --git a/src/shader_shim.moon b/src/shader_shim.moon index 76e0aec..77ad5a2 100644 --- a/src/shader_shim.moon +++ b/src/shader_shim.moon @@ -6,17 +6,21 @@ inputs = { "@height": win.height } +verts, frags = {}, {} shaders = setmetatable({},{ __index:(self, key) -> - vert_name = "shaders/" .. key .. ".vert" - frag_name = "shaders/" .. key .. ".frag" - vert = assert(am.load_string(vert_name), "Failed to find " .. vert_name) - frag = assert(am.load_string(frag_name), "Failed to find " .. frag_name) - vert_subbed = vert\gsub("@%b{}",(n) -> tostring(inputs[n])) - frag_subbed = frag\gsub("@%b{}",(n) -> tostring(inputs[n])) - succ, program = pcall(am.program, vert_subbed, frag_subbed) - if not succ - error(string.format("Failed compiling shader %q: %s vertex shader: %s fragment shader: %s", key, program, vert_subbed, frag_subbed)) - am.use_program(am.program(vert_subbed, frag_subbed)) + if not (verts[key] and frags[key]) + vert_name = "shaders/" .. key .. ".vert" + frag_name = "shaders/" .. key .. ".frag" + vert = assert(am.load_string(vert_name), "Failed to find " .. vert_name) + frag = assert(am.load_string(frag_name), "Failed to find " .. frag_name) + vert_subbed = vert\gsub("@%b{}",(n) -> tostring(inputs[n])) + frag_subbed = frag\gsub("@%b{}",(n) -> tostring(inputs[n])) + succ, program = pcall(am.program, vert_subbed, frag_subbed) + if not succ + error(string.format("Failed compiling shader %q: %s vertex shader: %s fragment shader: %s", key, program, vert_subbed, frag_subbed)) + verts[key] = vert_subbed + frags[key] = frag_subbed + am.use_program(am.program(verts[key], frags[key])) }) shaders diff --git a/src/shaders/land.frag b/src/shaders/land.frag index 1eb8d93..54ca24d 100644 --- a/src/shaders/land.frag +++ b/src/shaders/land.frag @@ -19,6 +19,7 @@ uniform float time; //used for noise uniform sampler2D atlas; uniform float nlamps; uniform float water; +//uniform sampler2D bubbles; varying vec2 worldxy; varying vec2 norm; @@ -78,8 +79,21 @@ void main() { float rng = random(vec2(coord.x, coord.y) + vec2(color, time)); color -= (pow(rng / 1.3, 10. * color)) * streamer; // add noise to water - if(water > 1.) + if(water > 1.){ color += (noise(coord.xy + vec2(time, time)) - 0.0) * 0.1; + } + if(water > 2.){ + color -= noise(coord.xy + vec2(time,time)) * 0.3; + } + /* + for(int i = 1; i < 1024; i++){ + vec4 bubble = texture2D(bubbles,vec2(i,0)); + /* + if(distance(bubble.xy, coord.xy) < 10.){ + color = 1.; + } + */ + //} /* */ if(color > 1.) gl_FragColor = highlight * normal.a; diff --git a/src/shaders/stars.lua b/src/shaders/stars.lua index 3e4138e..95938b4 100644 --- a/src/shaders/stars.lua +++ b/src/shaders/stars.lua @@ -68,7 +68,7 @@ node:action(function(self) self("bind").world_y = world.world_y local lamps = world.level.lamps_on_screen() for i,v in pairs(lamps) do - print("Setting lamp", i, "to", v) + --print("Setting lamp", i, "to", v) self("bind")["lamp" .. tostring(i)] = v end end) diff --git a/src/spawn_fish.moon b/src/spawn_fish.moon index 5bc090b..58c13d9 100644 --- a/src/spawn_fish.moon +++ b/src/spawn_fish.moon @@ -3,9 +3,92 @@ ecs = require("ecs") world = require("world") win = require("window") sprites = require("world.sprites") +colors = require("color") + +class BubbleGraphicsComponent extends world.GraphicsComponent + @loctbl = { + {-1,-1} + {-1,1} + {1,1} + {1,1} + {1,-1} + {-1,-1} + } + @max_bubbles = 6--128 + @bubble_anim = { + sprites.sphere_normal_1 + sprites.sphere_normal_2 + sprites.sphere_normal_3 + sprites.sphere_normal_4 + sprites.sphere_normal_5 + sprites.sphere_normal_6 + } + buf_size: () => + @@max_bubbles * 6 + populate_buf: (geom_buffer, uv_buffer, offset) => + -- we only need to store 1 frame info per 6 vertexes + @bubble_frames = am.buffer(@buf_size! / 6)\view("ubyte") + @buf = geom_buffer + @uv = uv_buffer + for i = 1, @@max_bubbles * 6-- must be divisible by 6 + geom_buffer[i] = vec3(0,0,0) + uv_buffer[i] = vec2(1,0) + join: (entity) => + super(entity) + aspect = win.width / win.height + program = @.node("use_program") + @cursor = 0 + @node\remove(program) + @node\append(am.blend("off")\append(program)) + bind = @.node("bind") + bind.water = 3 + for name, color in pairs(colors.am_lake_color) + bind[name] = color + @ent = entity + comp = @ + max_frames = @buf_size! / 6 + bf = @bubble_frames + uv = @uv + buf = @buf + @node\action(() -> + bubble_anim = comp.__class.bubble_anim + for i = 1,max_frames + last_frame = bf[i] + if last_frame < 6 + next_frame = last_frame + 1 + nuv = bubble_anim[next_frame] + ustart = (i-1) * 6 + uv[ustart + 1] = vec2(nuv.s1, nuv.t1) + uv[ustart + 2] = vec2(nuv.s2, nuv.t1) + uv[ustart + 3] = vec2(nuv.s2, nuv.t2) + uv[ustart + 4] = vec2(nuv.s2, nuv.t2) + uv[ustart + 5] = vec2(nuv.s1, nuv.t2) + uv[ustart + 6] = vec2(nuv.s1, nuv.t1) + bf[i] += 1 + + ) + add_bubble: (pos) => + h = 0.1 + --print("About to add bubble, cursor is", @cursor) + @bubble_frames[(@cursor / 6)+1] = 1 + for i = 1,6 + @buf[@cursor + i] = vec3(@@loctbl[i][1]*h + pos.x, @@loctbl[i][2]*h + pos.y, 0) + @cursor += 6 + if @cursor == (@@max_bubbles * 6) + @cursor = 0 + +[[ +bg = BubbleGraphicsComponent("graphic",{}) +bubble_ent = ecs.Entity(nil,{ + graphic: bg +}) +bubble = (pos) -> + -- Create a bubble + bg\add_bubble(pos) + ]] class FishGraphicComponent extends world.GraphicsComponent - @fish_size = 0.5 + @fish_size = 0.3 @static = false @loctbl = { {-1,-1} @@ -15,6 +98,7 @@ class FishGraphicComponent extends world.GraphicsComponent {1,-1} {-1,-1} } + @bubble_freq = 1 buf_size: () => 6 populate_buf: (geom_view, normal_view, offset) => @@ -26,7 +110,7 @@ class FishGraphicComponent extends world.GraphicsComponent for i = 1,6 loctbl = @@loctbl[i] geom_view[i] = vec3(@@loctbl[i][1] * h, @@loctbl[i][2] * h, -1.5) - uv = sprites.player_normal + uv = sprites.fish_normal normal_view[1] = vec2(uv.s1,uv.t1) normal_view[2] = vec2(uv.s1,uv.t2) normal_view[3] = vec2(uv.s2,uv.t2) @@ -42,20 +126,32 @@ class FishGraphicComponent extends world.GraphicsComponent assert(@pred, "Fish graphic must have a predicted component") @node\remove(program) @node\append(am.blend("alpha")\append(program)) + bind = @.node("bind") + for name, color in pairs(colors.am_lake_color) + bind[name] = color + bind.water = 3 @ent = entity + @last_bubble = am.current_time! comp = @ move: (pos) => h = @@fish_size / 2 --print("Calling move with", pos) --if @ent.state ~= "swimming" -- error("called move while not swimming") + --@phys.shape\moveTo(pos.x,pos.y) for i = 1,6 @buf[i] = vec3(@@loctbl[i][1] * h, @@loctbl[i][2] * h, -0.13) + vec3(pos.x, pos.y, 0) + --Fuck the bubles, the fish looks better without em + --if am.current_time! - @last_bubble > @@bubble_freq + --world.Bubble(pos) + --bubble(pos) + --print("should spawn bubble") + --@last_bubble = am.current_time! friction = 0.1 class FishPredictedComponent extends ecs.PredictedComponent new: (id) => - fish_speed = 0.00001 + fish_speed = 0.0001 super(id, {accel: vec2(0,0), vel: vec2(0,0), pos: vec2(0,0)}, "netc", { accel: () => --print("ent state:", @cc.state) @@ -82,6 +178,7 @@ class FishPredictedComponent extends ecs.PredictedComponent @gc = entity\get("graphic") @properties.pos = @net.properties.pos @cc = entity\get("control") + @pc = entity\get("phys") @ent = entity print("Got graphic component:",@gc, @gc.node) print("And my node is", @node) @@ -95,8 +192,13 @@ class FishPredictedComponent extends ecs.PredictedComponent if @ent.state == "catching" @gc.node.hidden=true else + --TODO: Fish debugging + --@gc.node.hidden=true @gc\move(@properties.pos) + @pc.shape\moveTo(@properties.pos.x, @properties.pos.y) +max_fish = 100 +nfish = 0 class Fish extends ecs.Entity new: (id, pos) => @width = 40 -- TODO: randomize fish width @@ -108,23 +210,48 @@ class Fish extends ecs.Entity phys: world.PhysicsComponent("phys",{},"circle",{pos.x, pos.y, @width / 256}) } super(id, components) + nfish += 1 destroy: (...) => super(...) - error("Where did fish go") class SpawnFishComponent extends ecs.Component new: (id, properties, spawnrect) => super(id, properties) + @spawnrect = spawnrect + @spawned = 0 + @last_spawned = world.sync_time! + @spawn_freq = 8 join: (entity) => - graphic = entity\get("graphic") + --TODO: only do this on the elected peer + graphic = entity\get("water") + assert(graphic, "Spawn fish must have a graphic node") + comp = @ + graphic.node\action(() => + if nfish < max_fish and world.sync_time! - comp.last_spawned > comp.spawn_freq + comp.last_spawned = world.sync_time! + comp\spawn_fish! + ) + for i = 1,10 do + @spawn_fish! + spawn_fish: () => + rngx = math.random(@spawnrect.x, @spawnrect.z) + rngy = math.random(@spawnrect.y, @spawnrect.w) + Fish(nil, vec2(rngx, rngy)) + [[ router = router.r! set_spawnable = () -> if router.state == "elected" graphic\action(() -> error("Spawn fish callback") ) - set_spawnable! - router\onchange(set_spawnable) + ]] + --set_spawnable! + --router\onchange(set_spawnable) + [[ + graphic\action(() -> + error("spawn fish component") + ) + ]] {:Fish, :SpawnFishComponent} diff --git a/src/ui.moon b/src/ui.moon index f729756..3c45b80 100644 --- a/src/ui.moon +++ b/src/ui.moon @@ -5,6 +5,7 @@ util = require("util") Button = require("ui.button") Joystick = require("ui.joystick") Textbox = require("ui.textbox") +Checkbox = require("ui.checkbox") ui_world = hc.new(64) @@ -32,6 +33,17 @@ ui.button = (x,y,width,height,text,controller_binds) -> ui.events.controller[bind] = button button +ui.checkbox = (x,y,width,height,text,controller_binds) -> + controller_binds = controller_binds or {} + checkbox = Checkbox(x,y,width,height,text) + ui.node\append(checkbox.node) + bounds = ui_world\rectangle(x,y,width,height) + ui.events.touch[bounds] = checkbox + ui.events.mouse[bounds] = checkbox + for bind in *controller_binds + ui.events.controller[bind] = checkbox + checkbox + ui.click = (x,y) -> ui_world\shapesAt(x,y) diff --git a/src/ui/checkbox.moon b/src/ui/checkbox.moon new file mode 100644 index 0000000..e76a790 --- /dev/null +++ b/src/ui/checkbox.moon @@ -0,0 +1,13 @@ +Button = require("ui.button") +class Checkbox extends Button + fire: (e) => + if e.event == "mouse_down" + if @depressed + @up! + else + @down! + --@down! + if @on + @on(@depressed) + +Checkbox diff --git a/src/ui/textbox.moon b/src/ui/textbox.moon index bdb8e13..e72de54 100644 --- a/src/ui/textbox.moon +++ b/src/ui/textbox.moon @@ -108,6 +108,7 @@ class Textbox extends Button elseif key == "kp_enter" or key == "enter" if @on @on(e) + @up! elseif key == "escape" @up! else diff --git a/src/world.moon b/src/world.moon index 60cb57b..d622351 100644 --- a/src/world.moon +++ b/src/world.moon @@ -68,6 +68,18 @@ x.fromscreen = (pos) -> vec2(globalx, globaly) x.level.on_land = (pos) -> not (pos.x > 10 or pos.x < -10 or pos.y > 10 or pos.y < -10) +x.level.in_sea = (pos) -> + pos.x > 15 or pos.x < -15 or pos.y > 15 or pos.y < -15 +-- Each pixel is 4 bytes, 1 byte per channel +x.level.bubble_buffer = am.buffer(1024 * 4 * 4, "dynamic") + +bubble_view = x.level.bubble_buffer\view("vec4") -- xy location, w time? +bubble_texture = am.texture2d(am.image_buffer(x.level.bubble_buffer, 1024 * 4, 1)) +class Bubble + @wrap = 1 + new: (pos) => + bubble_view[@@wrap] = vec4(pos.x, pos.y, -1, am.current_time!) + print("Bubble created") class PhysicsComponent extends ecs.Component new: (name, properties, shape, args) => @@ -90,7 +102,6 @@ class PhysicsComponent extends ecs.Component collisions: () => x.level.physics_world\collisions(@shape) - class GraphicsComponent extends ecs.Component new: (name, properties) => print("Got name", name, "and properties", properties) @@ -109,7 +120,7 @@ class GraphicsComponent extends ecs.Component 1, 0, 0, 0, 0, aspect, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 4 + 0, 0, 0, 3.5 ) binds = { MV: s_mv @@ -123,6 +134,7 @@ class GraphicsComponent extends ecs.Component world_y: x.world_y rot: 0 water: 0 + --bubbles: bubble_texture } for color, value in pairs(color.am_color) binds[color] = value @@ -175,4 +187,5 @@ class GraphicsComponent extends ecs.Component x.GraphicsComponent = GraphicsComponent x.PhysicsComponent = PhysicsComponent +x.Bubble = Bubble x diff --git a/src/worldgen.moon b/src/worldgen.moon index e4818d4..c3e7c94 100644 --- a/src/worldgen.moon +++ b/src/worldgen.moon @@ -17,5 +17,7 @@ cabin = require("prefab.cabin") char = player.ProtoPlayer() gc = char\get("graphic") nc = char\get("net") +[[ nc.properties.accel = vec2(0.1,0) nc.properties.last_update = am.current_time! - 0.1 +]] |
