diff --git a/package.json b/package.json index eda1baf10..3fa6ec5b4 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "audio-context": "^0.1.0", "bluebird": "^2.9.6", "bms": "^0.2.0", + "chance": "^0.7.3", "co": "^4.3.1", "debug": "^2.1.1", "jquery": "^2.1.3", diff --git a/public/skins/default/Note/DX.png b/public/skins/default/Note/DX.png index 079e5c51b..7df10cc2c 100644 Binary files a/public/skins/default/Note/DX.png and b/public/skins/default/Note/DX.png differ diff --git a/public/skins/default/skin.xml b/public/skins/default/skin.xml index 7f707e131..9889a90be 100644 --- a/public/skins/default/skin.xml +++ b/public/skins/default/skin.xml @@ -17,192 +17,190 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/skins/default/skin_data.yml b/public/skins/default/skin_data.yml index 8bc381d8d..ac25438da 100644 --- a/public/skins/default/skin_data.yml +++ b/public/skins/default/skin_data.yml @@ -5,7 +5,7 @@ styles: mode: iidx_l: - - { style: 'scratch', channel: 'sc' } + - { style: 'scratch', channel: 'SC' } - { style: 'white', channel: '1' } - { style: 'blue', channel: '2' } - { style: 'white', channel: '3' } diff --git a/public/skins/default/skin_template.jade b/public/skins/default/skin_template.jade index d6aec3a81..ed3a85625 100644 --- a/public/skins/default/skin_template.jade +++ b/public/skins/default/skin_template.jade @@ -12,17 +12,17 @@ skin(width='1280' height='720') // body sprite(image='Note/DX.png' frame=(cur.width + 'x64+' + cur.x + '+' + (22 + add)) - x=(x) y='y+4' width=(cur.width) height='height' + x=(x) y='y+4-12' width=(cur.width) height='height' visible=visible) // tail sprite(image='Note/DX.png' frame=(cur.width + 'x8+' + cur.x + '+' + (104 + add)) - x=(x) y='y+height+4' + x=(x) y='y+height+4-12' visible=visible) // head sprite(image='Note/DX.png' frame=(cur.width + 'x8+' + cur.x + '+' + (12 + add)) - x=(x) y='y' + x=(x) y='y-12' visible=visible) mixin notes(columns) @@ -32,7 +32,7 @@ skin(width='1280' height='720') - var ch = column.channel object(key='note_' + ch) sprite(image='Note/DX.png' frame=(cur.width + 'x12+' + cur.x + '+0') - x=(x) y='y') + x=(x) y='y - 12') object(key='longnote_' + ch) +longnote(x, cur, 0, '!active && !missed') +longnote(x, cur, 100, '!!active && !missed') @@ -50,8 +50,7 @@ skin(width='1280' height='720') sprite(image='NoteArea/Flash.png' x='1' y='476' blend='screen' alpha='1 - (t % 0.4) / 0.4') group(x='1' mask='283x550+1+0') - group(y='(t * 500 % 1500) - 500') - +notes(mode.iidx_l) + +notes(mode.iidx_l) // info panel sprite(image='InfoPanel/Background.png' y='616') diff --git a/src/app/index.js b/src/app/index.js index 7c678c068..d67e5e7f5 100644 --- a/src/app/index.js +++ b/src/app/index.js @@ -4,46 +4,44 @@ import * as Scintillator from 'bemuse/scintillator' import co from 'co' import $ from 'jquery' +import Chance from 'chance' + +import NoteArea from 'bemuse/game/note-area' export function main() { co(function*() { let skin = yield Scintillator.load('/skins/default/skin.xml') let context = new Scintillator.Context(skin) + let notes = generateRandomNotes() + let area = new NoteArea(notes) + let data = { } + let columns = ['SC', '1', '2', '3', '4', '5', '6', '7'] + + function updateNotes() { + let p = data.t * 180 / 60 + let entities = area.getVisibleNotes(p, p + (5 / 3), 550) + for (let column of columns) { + data[`note_${column}`] = entities.filter(entity => + !entity.height && entity.column === column) + data[`longnote_${column}`] = entities.filter(entity => + entity.height && entity.column === column) + .map(entity => Object.assign({ }, entity, { + active: entity.y + entity.height > 550 + })) + } + } - data['note_sc'] = [ { key: 1, y: 10 }, { key: 2, y: 160 } ] - data['note_1'] = [ { key: 1, y: 20 }, { key: 2, y: 150 } ] - data['note_2'] = [ { key: 1, y: 30 }, { key: 2, y: 140 } ] - data['note_3'] = [ { key: 1, y: 40 }, { key: 2, y: 130 } ] - data['note_4'] = [ { key: 1, y: 50 }, { key: 2, y: 120 } ] - data['note_5'] = [ { key: 1, y: 60 }, { key: 2, y: 110 } ] - data['note_6'] = [ { key: 1, y: 70 }, { key: 2, y: 90 } ] - data['note_7'] = [ { key: 1, y: 80 } ] - - data['longnote_sc'] = [ { key: 1, active: false, y: 210, height: 0 }, - { key: 3, active: true, y: 40, height: 100, - missed: true, }, ] - data['longnote_1'] = [ { key: 1, active: false, y: 220, height: 10 } ] - data['longnote_2'] = [ { key: 1, active: false, y: 230, height: 20 } ] - data['longnote_3'] = [ { key: 1, active: false, y: 240, height: 40, - missed: true, } ] - data['longnote_4'] = [ { key: 1, active: false, y: 250, height: 60 } ] - data['longnote_5'] = [ { key: 1, active: false, y: 260, height: 80 } ] - data['longnote_6'] = [ { key: 1, active: false, y: 270, height: 70, - missed: true, } ] - data['longnote_7'] = [ { key: 1, active: false, y: 280, height: 60 } ] - - for (let i of ['longnote_sc', 'longnote_1', 'longnote_2', 'longnote_3', - 'longnote_4', 'longnote_5', 'longnote_6', 'longnote_7', ]) { - let y = data[i][0].y + data[i][0].height + 50 - let height = 450 - y - data[i].push({ key: 2, y, height, active: true }) + for (let column of columns) { + data[`note_${column}`] = [] + data[`longnote_${column}`] = [] } let started = new Date().getTime() let draw = () => { data.t = (new Date().getTime() - started) / 1000 + updateNotes() context.render(data) } draw() @@ -57,6 +55,30 @@ export function main() { } +function generateRandomNotes() { + let notes = [] + let chance = new Chance(1234) + let columns = ['SC', '1', '2', '3', '4', '5', '6', '7'] + let nextId = 1 + for (let column of columns) { + let position = 4 + for (let j = 0; j < 2000; j ++) { + position += chance.integer({ min: 1, max: 6 }) / 8 + let length = chance.bool({ likelihood: 20 }) ? + chance.integer({ min: 1, max: 8 }) / 8 : 0 + let id = nextId++ + if (length > 0) { + let end = { position: position + length } + notes.push({ position: position, end, column, id }) + position = end.position + } else { + notes.push({ position: position, column, id }) + } + } + } + return notes +} + function showCanvas(view) { var { width, height } = view diff --git a/src/game/note-area.js b/src/game/note-area.js new file mode 100644 index 000000000..3d7b090e8 --- /dev/null +++ b/src/game/note-area.js @@ -0,0 +1,36 @@ + +import R from 'ramda' + +export class NoteArea { + constructor(notes) { + this._notes = R.sortBy(position, notes) + } + getVisibleNotes(lower, upper, height) { + return this._notes.filter(note => + note.end ? + !(note.position > upper || note.end.position < lower) : + !(note.position > upper || note.position < lower)) + .map(note => { + if (!note.end) { + return { key: note.id, y: y(lower, upper, note.position, height), + column: note.column, } + } else { + let head = y(lower, upper, note.position, height) + let tail = y(lower, upper, note.end.position, height) + return { key: note.id, y: Math.min(head, tail), + height: Math.abs(head - tail), + column: note.column, } + } + }) + } +} + +export default NoteArea + +function y(lower, upper, position, height) { + return height - (position - lower) / (upper - lower) * height +} + +function position(event) { + return event.position +} diff --git a/src/scintillator/expression/index.js b/src/scintillator/expression/index.js index 608fd2c28..cca63e565 100644 --- a/src/scintillator/expression/index.js +++ b/src/scintillator/expression/index.js @@ -5,7 +5,9 @@ let log = debug('scintillator:expression') import parser from './parser.pegjs' function createFunction(code) { - return eval('(function(get) { return ' + code + ' })') + let fn = eval('(function(get) { return ' + code + ' })') + fn.displayName = '(' + code + ')' + return fn } export function Expression(text) { diff --git a/src/scintillator/nodes/lib/instance.js b/src/scintillator/nodes/lib/instance.js index 1a9c15a44..3e63d7c1c 100644 --- a/src/scintillator/nodes/lib/instance.js +++ b/src/scintillator/nodes/lib/instance.js @@ -17,8 +17,9 @@ export function Instance(context, callback) { }, bind(...pipeline) { let sideEffect = onChange(pipeline.pop()) - helper.onData(function(value) { - for (let f of pipeline) value = f(value) + helper.onData(function applyBinding(value) { + // using var here to optimize + for (var i = 0; i < pipeline.length; i ++) value = pipeline[i](value) sideEffect(value) }) },