|
|
@ -2,8 +2,10 @@ |
|
|
|
:slides |
|
|
|
(array |
|
|
|
(slide-data :heading "Driving code with data" :body "Macoy Madson") |
|
|
|
(slide-data :heading "Setting the stage") |
|
|
|
(slide-data :heading "Setting the stage" |
|
|
|
:body "(Art by Pixel-boy. Creative Commons Zero license.)") |
|
|
|
(slide-data :heading "First pass" |
|
|
|
:is-code true |
|
|
|
:body "if shouldShootFireball(): |
|
|
|
{ |
|
|
|
makeFireball(); |
|
|
@ -13,7 +15,9 @@ for each fireball: |
|
|
|
{ |
|
|
|
updateFireballs(); |
|
|
|
}") |
|
|
|
(slide-data :heading "What about ice storms?" :body "if shouldShootFireball(): |
|
|
|
(slide-data :heading "What about ice storms?" |
|
|
|
:is-code true |
|
|
|
:body "if shouldShootFireball(): |
|
|
|
{ |
|
|
|
makeFireball(); |
|
|
|
} |
|
|
@ -36,6 +40,7 @@ heat seeker |
|
|
|
...") |
|
|
|
(slide-data :heading "We have a problem") |
|
|
|
(slide-data :heading "Second pass: sharing code" |
|
|
|
:is-code true |
|
|
|
:body "for each projectile in projectiles: |
|
|
|
{ |
|
|
|
updateProjectile(projectile); |
|
|
@ -48,4 +53,157 @@ heat seeker |
|
|
|
- Complexity spreads") |
|
|
|
(slide-data :heading "What are computers good at?") |
|
|
|
(slide-data :heading "Storing and manipulating data") |
|
|
|
(slide-data :heading "Describe the behavior in data"))) |
|
|
|
(slide-data :heading "Describe the behavior in data" |
|
|
|
:is-code true |
|
|
|
:body "struct Power |
|
|
|
{ |
|
|
|
struct OnActivate |
|
|
|
{ |
|
|
|
String makeParticle; |
|
|
|
vec2 startVelocity; |
|
|
|
} onActivate; |
|
|
|
|
|
|
|
struct OnUpdate |
|
|
|
{ |
|
|
|
MovementType movement; |
|
|
|
vec2 acceleration; |
|
|
|
} onUpdate; |
|
|
|
|
|
|
|
struct OnEnemyHit |
|
|
|
{ |
|
|
|
StatusEffect effect; |
|
|
|
int magnitude; |
|
|
|
} onEnemyHit; |
|
|
|
}") |
|
|
|
(slide-data :heading "We now have templates" |
|
|
|
:is-code true |
|
|
|
:body "Power fireball = |
|
|
|
{ |
|
|
|
.onActivate = |
|
|
|
{ |
|
|
|
.makeParticle = \"fireball\", |
|
|
|
.startVelocity = {5.f, 0.f}, |
|
|
|
}, |
|
|
|
.onUpdate = |
|
|
|
{ |
|
|
|
.movement = MovementType_Projectile, |
|
|
|
}, |
|
|
|
.onEnemyHit |
|
|
|
{ |
|
|
|
.effect = StatusEffect_Damage, |
|
|
|
.magnitude = 200, |
|
|
|
}, |
|
|
|
}") |
|
|
|
(slide-data :heading "Move all behaviors into the same handler") |
|
|
|
(slide-data :heading "Design can now make variations" |
|
|
|
:body "But all special new types need a programmer. |
|
|
|
|
|
|
|
Lots of one-off booleans: doTheSpecialIceStormThing") |
|
|
|
(slide-data :heading "Can we take the data approach even further?") |
|
|
|
(slide-data :heading "Generic \"operation\" structure" |
|
|
|
:is-code true |
|
|
|
:body "struct Operation |
|
|
|
{ |
|
|
|
}") |
|
|
|
(slide-data :heading "Now we can do more") |
|
|
|
(slide-data :heading "Great, but designers still want more!" |
|
|
|
:body "I want it to do X only if Y is true |
|
|
|
|
|
|
|
It should do X only sometimes, e.g. randomly") |
|
|
|
(slide-data :heading "Our operations are data" |
|
|
|
:body "What if operations change how they themselves are executed?") |
|
|
|
(slide-data :heading "New operations" |
|
|
|
:is-code true |
|
|
|
:body "Label |
|
|
|
GoToLabel |
|
|
|
SetValue |
|
|
|
IfValueEquals |
|
|
|
Else |
|
|
|
EndIf |
|
|
|
...") |
|
|
|
(slide-data :heading "Operations now change control flow" |
|
|
|
:body "Manipulate the index while we iterate") |
|
|
|
(slide-data :heading "Wow") |
|
|
|
(slide-data :heading "We can now make huge variations") |
|
|
|
(slide-data :heading "But people hate writing these" |
|
|
|
:body "All those {} and , are slowing people down") |
|
|
|
(slide-data :heading "Let's give them a better syntax" |
|
|
|
:is-code true |
|
|
|
:body "IfEqual distance 5 |
|
|
|
MakeParticle fireball |
|
|
|
EndIf") |
|
|
|
(slide-data :heading "How should we implement this?" |
|
|
|
:is-code true |
|
|
|
:body "for each word in file: |
|
|
|
if word == \"IfEqual\": |
|
|
|
operations.append({Operation_IfEqual, ...}); |
|
|
|
else if word == \"MakeParticle\" |
|
|
|
...") |
|
|
|
(slide-data :heading "Looks familiar?" |
|
|
|
:is-code true |
|
|
|
:body "for each word in file: |
|
|
|
if word == \"IfEqual\": |
|
|
|
operations.append({Operation_IfEqual, ...}); |
|
|
|
else if word == \"MakeParticle\" |
|
|
|
...") |
|
|
|
(slide-data :heading "We can do better!" |
|
|
|
:is-code true |
|
|
|
:body "struct OperationReader |
|
|
|
{ |
|
|
|
String name; |
|
|
|
OperationType type; |
|
|
|
Array<ArgumentReader> arguments; |
|
|
|
} |
|
|
|
|
|
|
|
struct ArgumentReader |
|
|
|
{ |
|
|
|
ArgumentDestination outputTo; |
|
|
|
} |
|
|
|
") |
|
|
|
(slide-data :heading "Our parser is now data-driven" |
|
|
|
:is-code true |
|
|
|
:body "for each word, index in file: |
|
|
|
for each reader in operationReaders: |
|
|
|
if word == reader.name |
|
|
|
Operation operation; |
|
|
|
operation.type = reader.type; |
|
|
|
operation.arguments = readArguments(reader, file, index) |
|
|
|
|
|
|
|
function readArguments(reader, file, wordIndex): |
|
|
|
for each argument in reader.arguments: |
|
|
|
if argument.outputTo == String: |
|
|
|
parseString(file[wordIndex]) |
|
|
|
if argument.outputTo == Number: |
|
|
|
parseNumber(file[wordIndex]) |
|
|
|
wordIndex++") |
|
|
|
(slide-data :heading "Now they're off to the races" |
|
|
|
:is-code true |
|
|
|
:body " |
|
|
|
if blah: if blah: |
|
|
|
blah blah blah blah 2 |
|
|
|
EndIf EndIf") |
|
|
|
(slide-data :heading "We just made a programming language!" |
|
|
|
:body "That wasn't so hard, was it?") |
|
|
|
(slide-data :heading "There are problems with this approach" |
|
|
|
:body "- Need tools for debugging |
|
|
|
- Less expressive power than native language |
|
|
|
- Performance impact |
|
|
|
- Spreading to problems it wasn't designed for |
|
|
|
- Feature creep without language redesign |
|
|
|
- Non-programmers doing programming") |
|
|
|
(slide-data :heading "Questions to ask") |
|
|
|
(slide-data :heading "Can I express this problem with data?") |
|
|
|
(slide-data :heading "Can I author that data in a better way?") |
|
|
|
(slide-data :heading "How do I expect the problem, data, |
|
|
|
and feature to grow?" |
|
|
|
:body "How are they actually growing?") |
|
|
|
(slide-data :heading "Am I building a complicated generic system |
|
|
|
before knowing it is necessary?") |
|
|
|
(slide-data :heading "In conclusion" |
|
|
|
:body "Doing this is not hard, |
|
|
|
knowing when to do this, and to what extent, |
|
|
|
is hard. |
|
|
|
|
|
|
|
That doesn't mean it shouldn't be done, but does |
|
|
|
mean it should be done carefully.") |
|
|
|
(slide-data :heading "Questions?")) |
|
|
|