Norns: sketches

How about a thread where we share small experiments that don’t quite need it into their own thread, or work in progress?

Pong

Like, shall we play a two-player game of Pong?

Video

Two players, first to reach 5 goals.

  • Player 1, on E1.
  • Player 2, on E3.
  • Reset, on K2.
local game = { frame = 0, difficulty = 20 }
local viewport = { size = { w = 128, h = 64 } }
local ball = { pos = { x = 0, y = 0 }, dir = 0, angle = 1, speed = 0.5, size = 3, moving = false, owned = true }
local players = { a = { pos = 0, score = 0 }, b = { pos = 0, score = 0 } }

function init()
  -- Render Style
  screen.level(15)
  screen.aa(0)
  screen.line_width(1)
  reset()  
  reset_score()
end

function start()
  reset()
  ball.moving = true
  ball.dir = 1
end

function reset()
  game.frame = 0
  game.difficulty = 20
  ball.pos = {x = viewport.size.w/2, y = viewport.size.h/2}
  ball.angle = 0
  ball.speed = 2
  ball.moving = false
  players.a.pos = (viewport.size.w/2) - (game.difficulty/2)
  players.b.pos = (viewport.size.w/2) - (game.difficulty/2)
end

function reset_score()
  players.a.score = 0
  players.b.score = 0
end

function run()
  -- Move ball
  if ball.moving == true then
    ball.pos.y = ball.pos.y + (ball.speed * ball.dir)
    ball.pos.x = ball.pos.x + ball.angle
    game.difficulty = clamp(20 - math.floor(game.frame/200),10,20)
    game.frame = game.frame + 1
  end
  -- Collide with sides
  if ball.pos.x > viewport.size.w - 2 or ball.pos.x < 1 then
    ball.angle = ball.angle * -1
  end
  -- Collide with player a
  if ball.pos.y < 2 and touch(players.a,ball.pos) then
    collide(players.a,ball)
  end
  -- Collide with player b
  if ball.pos.y > viewport.size.h - 3 and touch(players.b,ball.pos) then
    collide(players.b,ball)
  end
  -- Goals
  if ball.pos.y < -6 then
    goal(players.b)
  end
  if ball.pos.y > viewport.size.h + 6 then
    goal(players.a)
  end
  if players.a.score > 4 or players.b.score > 4 then
    reset()
    reset_score()
  end
end

function touch(player,pos)
  return pos.x > player.pos - ball.size and pos.x < player.pos + game.difficulty + ball.size
end

function collide(player,ball)
  ball.dir = ball.dir * -1  
  ball.angle = clamp(math.floor((((ball.pos.x - (player.pos + (game.difficulty/2)))/4) * 0.25) * 100)/40,-0.8,0.8)
  ball.speed = clamp(ball.speed + 0.05,0,2)
end

function goal(player)
  player.score = player.score + 1
  reset()
end

-- Gestures

function key(n,z)
  if n == 2 and z == 1 then
    reset()
    reset_score()
  end
end

function move(player,d)
  if ball.moving == false then
    start()
  end
  player.pos = clamp(player.pos + d,0,128 - game.difficulty)
end

function enc(n,d)
  if n == 1 then
    move(players.a,-d)
  elseif n == 3 then
    move(players.b,d)
  end
end

-- Render

function draw_val(val,id)
  local spacing = 15
  local size = { w = 12, h = 4 }
  local pos = { x = viewport.size.w - size.w, y = (viewport.size.h/2) - size.h - spacing + 4 }
  if id == 1 then
    pos.y = (viewport.size.h/2) - size.w + size.h + spacing + 6
  end

  if val == 0 then screen.move(pos.x, pos.y) ; screen.line(pos.x+size.w, pos.y) ; screen.line(pos.x+size.w, pos.y+size.h) ; screen.line(pos.x, pos.y+size.h) ; screen.line(pos.x, pos.y) ; screen.close() ; screen.stroke() end
  if val == 1 then screen.move(pos.x+size.w, pos.y + size.h/2) ; screen.line(pos.x, pos.y+ size.h/2) ; screen.stroke() end
  if val == 2 then screen.move(pos.x+size.w, pos.y-1) ;  screen.line(pos.x+size.w, pos.y+ size.h) ; screen.line(pos.x+(size.w/2), pos.y+ size.h) ; screen.line(pos.x+(size.w/2), pos.y) ; screen.line(pos.x, pos.y) ; screen.line(pos.x, pos.y+size.h) ;  screen.stroke() end
  if val == 3 then screen.move(pos.x+size.w, pos.y-1); screen.line(pos.x+size.w, pos.y+ size.h); screen.line(pos.x, pos.y+size.h); screen.line(pos.x, pos.y-1); screen.move(pos.x+(size.w/2), pos.y+size.h); screen.line(pos.x+(size.w/2), pos.y); screen.stroke() end
  if val == 4 then screen.move(pos.x+size.w, pos.y) ; screen.line(pos.x+(size.w/2), pos.y) ; screen.line(pos.x+(size.w/2), pos.y+size.h) ; screen.move(pos.x+size.w,pos.y+size.h) ; screen.line(pos.x-1,pos.y+size.h) ; screen.stroke() end
end

function redraw()
  screen.clear()
  -- Score
  screen.level(1)
  draw_val(players.a.score,0)
  draw_val(players.b.score,1)
  -- Court
  for i = viewport.size.w,1,-1 do 
    if i % 2 == 1 then
      screen.pixel(math.floor(i),(viewport.size.h/2))
    end
  end
  screen.fill()
  screen.level(15)
  -- Player A
  screen.move(players.a.pos, 1)
  screen.line(players.a.pos + game.difficulty, 1)
  -- Player B
  screen.move(players.b.pos, viewport.size.h)
  screen.line(players.b.pos + game.difficulty, viewport.size.h)
  screen.stroke()
  -- Ball
  local x = ball.pos.x
  local y = ball.pos.y
  screen.pixel(x, y)
  screen.fill()
  screen.update()
end

-- Utils

function clamp(val,min,max)
  return val < min and min or val > max and max or val
end

function update(sec)
  run()
  redraw()
end

function midi_to_hz(note)
  return (440 / 32) * (2 ^ ((note - 9) / 12))
end

-- Interval

re = metro.init()
re.time = 1.0 / 15
re.event = function()
  update()
end
re:start()
33 Likes

This is crazy cool! :dizzy_face::dizzy_face::dizzy_face:

Very nice. I built breakout today, just hooking up midi output when you break a block. Something about this screen is fun to code for, beyond music even :slight_smile:

5 Likes

Yay!

a quick thing…

I have started on porting the f0plugins from fredrik olofsson to norns engines. These are supercollider emulations of old game chips.

I’ve done a basic implementation of the Atari2600 and SN76489. Started on NES2, but that’s gonna take some serious work.

I started on Space Invaders a long while back and need to revisit. :slight_smile:

15 Likes

21 posts were split to a new topic: Sex positivity, word choice, &c

@okyeron That’s amazing, I would love the sounds to be really basic.
I’ll look into that :slight_smile: I’ve started looking at how the other applications handle sound synthesis.

I’ve changed the name, I didn’t realized it had such that kind of baggage around synths. That’s unfortunate.

@crim I will look into that, I want that too :slight_smile:

8 Likes

Improved the interface to fit with the classic style of the game.

3 Likes

i moved a lot of posts about the old name (“Porns”) to a new topic:

if you have things to say about the old name, that would be the place

7 Likes

Came for the pr0nz, stayed for the Pong. Glad you are taking part in norns development! Much looking forward to seeing what else you come up with!

6 Likes

this looks awesome. i think it’d be really cool if the x and y positions of the ball were mapped to midi or modulated some synth engine or effects params. I have a dream of many little norns games where all the controls and animations are also modulators.

9 Likes

I have a lot of neat little sketches that shouldn’t really have their own threads, so I will post them here, and you are all welcome to do the same :slight_smile:

Here’s one:

Etch N Sketch

local viewport = { width = 128, height = 64 }
local focus = { x = 0, y = 0, is_drawing = true }

-- Main

function init()
  -- Render Style
  screen.level(15)
  screen.aa(0)
  screen.line_width(1)
  -- Center focus
  focus.x = 0
  focus.y = viewport.height-1
  -- Render
  erase()
end

function toggle_drawing()
  if focus.is_drawing == true then
    focus.is_drawing = false
  else
    focus.is_drawing = true
  end
end

-- Interactions

function key(id,state)
  if id == 2 and state == 1 then
    erase()
  elseif id == 3 and state == 1 then
     toggle_drawing()
  end
end

function enc(id,delta)
  if id == 2 then
    focus.x = clamp(focus.x + delta,0,viewport.width-1)
  elseif id == 3 then
    focus.y = clamp(focus.y - delta,0,viewport.height-1)
  end
  redraw()
end

-- Render

function erase()
  screen.clear()
  draw_focus()
  screen.update()
end

function draw_focus()
  if focus.is_drawing == true then
    screen.pixel(focus.x,focus.y)
  end
  screen.fill()
end

function redraw()
  draw_focus()
  screen.update()
end

-- Utils

function clamp(val,min,max)
  return val < min and min or val > max and max or val
end
18 Likes

Makes me think of the OP-1 sketch sequencer :slight_smile:

3 Likes

@neauoire I love this! now to make it sequence lol

btw, re:

-- Utils
function clamp(val,min,max)
  return val < min and min or val > max and max or val
end

there is a norns util for clamping

util.clamp(value, min, max)
3 Likes

I’m working on something MASSIVE.

I should have a demo tomorrow. This needs a grid. Can’t wait to show you have I’ve been cooking.

27 Likes

Hype is real in 20 characters

1 Like

I’m glad to be spending a month in Europe, but all this time away from Norns - especially in light of @neauoire’s recent work - has been annoying.

5 Likes

head explodes in 255 chars
(the first stands for speachless)

1 Like

This is why I am bringing Norns with me to Europe :wink:

6 Likes

Sorry for building hype and not delivering, I’ve been going back and forth between two designs yesterday, but I think I got it now. Tonight I definitely will have a something to show for this :fist:

13 Likes

scripts within scripts! let’s all go down the rabbit hole together… :rabbit2:

4 Likes