if(scriptographer.version < 2.9) { Dialog.alert('Road.js only works on versions 2.9 of Scriptographer or higher. Please upgrade Scriptographer first.'); } else { var values = { roadSize: 10, maxSpeed: 5, minSpeed: 0, count: 0, steering: 1.5 } var components = { roadSize: { label: 'Size', range: [0, 100], steppers: true }, maxSpeed: { label: 'Max Speed', range: [0, 50], steppers: true }, steering: { label: 'Steering', range: [1, 2], type: 'slider', width: 100 }, help: { type: 'button', value: 'Instructions', onClick: function() { if(this.value == 'Instructions') { this.value = 'Close Instructions'; components.instructions.value = '\n- Click and Drag to create a Road\n' + '- Steer it with Left and Right arrow keys\n' + '- Up to accelerate, Down to brake\n' + '- Ctrl for handbrake\n' + '- Hold down Shift to make Road go under other roads\n' + '- Shift, Click and Drag to create multiple roads'; components.instructions.height = null; } else { this.value = 'Instructions'; components.instructions.value = ''; components.instructions.height = 0; } } }, instructions: { type: 'text', multiline: true, fullSize: true, value: '', height: 0 } } var palette = new Palette('Roads', components, values); // var roadGroup = document.activeLayer.children['roads']; // if(!roadGroup) { // roadGroup = new Group(); // roadGroup.name = 'roads'; // } Road = Base.extend({ initialize: function(position, rotation) { this.vector = new Point(1, 1); this.vector.angle = rotation; this.position = position; this.maxSteer = 4.5; this.speed = 0; this.friction = 0.98; this.roadSize = values.roadSize; this.group = Road.getGroup(); this.createPaths(); this.draw(); this.shiftDown = false; this.id = values.count; values.count++; }, createPaths: function() { if(this.leftLine && this.leftLine.isValid()) { if(this.leftLine.isAbove(this.group)) { this.group.appendTop(this.leftLine.parent); } else { this.group.appendBottom(this.leftLine.parent); } } this.background = new Path() { strokeColor: null, fillColor: '#FFFFFF', name: 'background' }; this.rightLine = new Path(); this.rightLine.name = 'rightLine'; this.leftLine = new Path(); this.leftLine.name = 'leftLine'; this.rightLine.style = this.leftLine.style = { strokeColor: 'black', fillColor: null, dashArray: null, strokeWidth: this.roadSize / 5, strokeCap: 'round' }; var dashOffset = 0; if(this.centerLine) dashOffset = (this.centerLine.dashOffset + this.centerLine.length); this.centerLine = new Path() { dashArray: [this.roadSize / 2, this.roadSize * 0.8], dashOffset: dashOffset, fillColor: null, strokeColor: 'black', strokeWidth: this.roadSize / 10, name: 'centerLine', strokeCap: 'round' }; var group = new Group([this.rightLine, this.leftLine, this.centerLine, this.background]); group.name = 'section'; if(Key.isDown('shift')) { group.moveBelow(this.group); } else { group.moveAbove(this.group); } if(this.lastLeft) { this.leftLine.add(this.lastLeft); this.rightLine.add(this.lastRight); this.background.add(this.lastRight); this.background.add(this.lastLeft); this.centerLine.add(this.lastPosition); } }, needsSplit: function() { return this.centerLine.segments.length > 30; }, isValid: function() { return this.background.isValid(); }, remove: function() { roads.slice(this.id, 1); }, turn: function(direction) { if(this.speed >= 0.01) { if (this.speed < 3 && this.speed >= 0) { this.vector.angle += direction * this.speed * 2; } else if (this.speed < 0) { this.vector.angle += direction * this.speed / 2; } else { this.vector.angle += direction * this.maxSteer * values.steering; } this.speed *= this.friction; } }, forward: function() { this.speed += 0.3; this.speed = Math.min(values.maxSpeed, this.speed); }, reverse: function() { this.speed -= 0.3; if(this.speed < values.minSpeed) this.speed = values.minSpeed; }, handbrake: function() { this.speed -= this.speed / 10; if (Key.isDown('right')) { this.vector.angle -= this.speed / 2; } if (Key.isDown('left')) { this.vector.angle += this.speed / 2; } }, draw: function() { if(this.isValid()) { var vec = this.vector.clone(); vec.length = Math.abs(this.speed); this.speed = this.speed * this.friction; if(this.speed < 0) { this.position -= vec; } else { this.position += vec; } vec.angle += 90; vec.length = this.roadSize; var left = this.position + vec; var right = this.position - vec; if(this.lastLeft) { var hitResult = this.background.hitTest(left, 0.001) || this.background.hitTest(right, 0.001); if(this.speed > 1 && hitResult) { this.createPaths(); } } if(Math.abs(this.speed) > 0) { if(this.lastVector && this.leftLine.segments.length > 2 && this.lastVector.angle == this.vector.angle) { this.leftLine.segments.last.point = left; this.rightLine.segments.last.point = right; this.background.segments.last.point = left; this.background.segments.first.point = right; this.centerLine.segments.last.point = this.position; } else { this.leftLine.add(left); this.rightLine.add(right); this.background.add(left); this.background.insert(0, right); this.centerLine.add(this.position); } this.lastLeft = left; this.lastRight = right; } this.lastVector = this.vector.clone(); this.lastPosition = this.position.clone(); } else { print('invalid'); var index; for(var i = 0; i < roads.length; i++) { if(roads[i].id == this.id) index = i; } roads.splice(index, 1); for(var i = 0; i < roads.length; i++) { var road = roads[i]; if(road.id > this.id) road.id = road.id - 1; } } }, statics: { getGroup: function() { if(document && (!this.roadGroup || !this.roadGroup.isValid())) { var roadGroup = document.activeLayer.children['roads']; if(roadGroup && roadGroup.isValid()) { this.roadGroup = roadGroup; } else { this.roadGroup = new Group(); this.roadGroup.name = 'roads'; } } return this.roadGroup }, cleanUp: function() { var roadGroup = document.activeLayer.children['roads']; if(roadGroup) { var items = document.activeLayer.children; for(var i = 0; i < items.length; i++) { var item = items[i]; if(item.name == 'section') { if(item.isAbove(roadGroup)) { roadGroup.appendTop(item); } else { roadGroup.appendBottom(item); } } } } } } }); var roads = []; // move any existing road sections that aren't in the roads group // into the roads group: if(document) Road.cleanUp(); function onMouseUp(event) { if(!Key.isDown('shift') && roads.length) roads.pop(); var road = new Road(event.point, event.delta.angle); road.speed = event.delta.length / 20; if(road.speed < 0.05) road.speed = 0.05; road.draw(); roads.push(road); } var shiftDown = false; function moveRoad() { for(var i = 0; i < roads.length; i++) { var road = roads[i]; road.group = Road.getGroup(); if(Key.isDown('shift')) { if(!road.shiftDown) { if(!road.group.hitTest(road.lastLeft) && !road.group.hitTest(road.lastRight) && !road.group.hitTest(road.lastPosition)) { road.createPaths(); road.shiftDown = true; } } } else { if(road.shiftDown || road.needsSplit()) { if(!road.group.hitTest(road.lastLeft) && !road.group.hitTest(road.lastRight) && !road.group.hitTest(road.lastPosition)) { road.createPaths(); road.shiftDown = false; } } } if(Key.isDown('left')) road.turn(-1); if(Key.isDown('right')) road.turn(1); if(Key.isDown('up')) road.forward(); if(Key.isDown('down')) road.reverse(); if(Key.isDown('control')) road.handbrake(); road.draw(); } } var movingRoad = setInterval(moveRoad, 30); }