generated from macoy/gamelib-project-template
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
9.0 KiB
316 lines
9.0 KiB
(presentation-data
|
|
:slides
|
|
(array
|
|
(slide-data :heading "Driving code with data" :body "Macoy Madson")
|
|
(slide-data :heading "Setting the stage" :trigger "show-ground")
|
|
(slide-data :heading "Setting the stage" :trigger "enter-wizard")
|
|
(slide-data :heading "Setting the stage" :trigger "enter-boar")
|
|
(slide-data :heading "Setting the stage"
|
|
:body "(Art by Pixel-boy)")
|
|
(slide-data :heading "First pass"
|
|
:is-code true
|
|
:body "if shouldShootFireball():
|
|
{
|
|
makeFireball();
|
|
}
|
|
|
|
for each fireball:
|
|
{
|
|
updateFireballs();
|
|
}")
|
|
(slide-data :heading "What about ice storms?"
|
|
:is-code true
|
|
:body "if shouldShootFireball():
|
|
{
|
|
makeFireball();
|
|
}
|
|
else if shouldShootIceStorm():
|
|
{
|
|
makeIceStorm();
|
|
}
|
|
|
|
for each fireball in fireballs:
|
|
{
|
|
updateFireball(fireball);
|
|
}
|
|
for each iceStorm in iceStorms:
|
|
{
|
|
updateIceStorm(iceStorm);
|
|
}")
|
|
(slide-data :heading "We want" :body "rock smash
|
|
magma ball
|
|
heat seeker
|
|
boomerang
|
|
...")
|
|
(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);
|
|
|
|
function updateProjectile(projectile):
|
|
projectile.x += projectile.velocityX
|
|
|
|
if projectile.isFireball:
|
|
if projectile.x > 500:
|
|
projectile.velocityX = 5;
|
|
else if projectile.isIceStorm:
|
|
...")
|
|
(slide-data :heading "It works, but..."
|
|
:body "The code is a mess:
|
|
|
|
- Special cases everywhere
|
|
- No easy way to add new types or classes of things
|
|
- No clear centralization of functionality
|
|
- Complexity spreads: There is rarely only one place
|
|
where all behavior is kept!")
|
|
(slide-data :heading "What are computers good at?")
|
|
(slide-data :heading "What are computers good at?"
|
|
:body "Storing and manipulating 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 "Parameterized powers"
|
|
: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 "We 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
|
|
{
|
|
OperationType type;
|
|
String argumentA;
|
|
String argumentB;
|
|
}
|
|
|
|
enum OperationType
|
|
{
|
|
makeParticle,
|
|
setVelocityX,
|
|
setMovementType,
|
|
doCombatEffect,
|
|
}")
|
|
(slide-data :heading "Now we have more control"
|
|
:is-code true
|
|
:body "Power fireball =
|
|
{
|
|
onActivate =
|
|
{
|
|
{type = makeParticle, argumentA = \"fireball\",
|
|
{type = setVelocityX, argumentA = \"5\"},
|
|
},
|
|
onUpdate =
|
|
{
|
|
{type = setMovementType,
|
|
argumentA = \"MovementType_Projectile\"},
|
|
},
|
|
onEnemyHit =
|
|
{
|
|
{type = setVelocityX, argumentA = \"0\"},
|
|
{type = doCombatEffect,
|
|
argumentA = \"StatusEffect_Damage\",
|
|
argumentB = \"200\"},
|
|
},
|
|
}")
|
|
(slide-data :heading "Great, but we want more power!"
|
|
:body "Do X only if Y is true
|
|
|
|
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
|
|
End
|
|
...")
|
|
(slide-data :heading "Operations now change control flow"
|
|
:is-code true
|
|
:body "for each operation, operationIndex in power.onUpdateOperations:
|
|
if operation.type == IfEquals:
|
|
if operation.argumentA != operation.argumentB:
|
|
operationIndex = findEndOperation()
|
|
|
|
else if operation.type == makeParticle:
|
|
makeParticle(operation.argumentA)
|
|
...")
|
|
(slide-data :heading "We can now make huge variations")
|
|
(slide-data :heading "But we hate writing these"
|
|
:body "{type = IfEquals, argumentA = \"positionX\", argumentB = \"500\"},
|
|
{type = setVelocityX, argumentA = \"5\"},
|
|
{type = Else},
|
|
{type = setVelocityX, argumentA = \"15\"},
|
|
{type = End}
|
|
...")
|
|
(slide-data :heading "But we hate writing these"
|
|
:body "All these {} and , are slowing us down")
|
|
(slide-data :heading "Let's imagine a better syntax"
|
|
:is-code true
|
|
:body "IfEquals positionX 500
|
|
setVelocityX 5
|
|
Else
|
|
setVelocityX 15
|
|
End")
|
|
(slide-data :heading "How should we implement this?"
|
|
:is-code true
|
|
:body "for each word in file:
|
|
if word == \"IfEqual\":
|
|
operations.append({IfEqual, ...});
|
|
else if word == \"MakeParticle\"
|
|
...")
|
|
(slide-data :heading "Looks familiar?"
|
|
:is-code true
|
|
:body "for each word in file:
|
|
if word == \"IfEqual\":
|
|
operations.append({IfEqual, ...});
|
|
else if word == \"MakeParticle\"
|
|
...
|
|
|
|
vs.
|
|
|
|
if projectile.isFireball:
|
|
if projectile.x > 500:
|
|
projectile.velocityX = 5;
|
|
else if projectile.isIceStorm:
|
|
...")
|
|
(slide-data :heading "We can do better!"
|
|
:is-code true
|
|
:body "struct OperationReader
|
|
{
|
|
String name;
|
|
OperationType type;
|
|
int numArguments;
|
|
}
|
|
|
|
OperationReader readers =
|
|
{{\"IfEquals\", IfEqual, 2},
|
|
{\"MakeParticle\", MakeParticle, 1},}
|
|
")
|
|
(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.numArguments, file, &index)
|
|
|
|
function readArguments(numArguments, file, *wordIndex):
|
|
arguments = []
|
|
each in range(numArguments):
|
|
arguments.append(file[wordIndex])
|
|
wordIndex++")
|
|
(slide-data :heading "Our parser is now data-driven"
|
|
:body "This gives us several benefits:
|
|
|
|
- Easier to add new operations
|
|
(One line rather than copy-pasting if block)
|
|
- Easier to bake in per-operation validation
|
|
- Possible to enumerate all possible operations, which
|
|
makes autocomplete, help, typo suggestions possible")
|
|
(slide-data :heading "Now we're off to the races"
|
|
:trigger "power-cycle-display"
|
|
:is-code true)
|
|
(slide-data :heading "We just made a programming language!"
|
|
:body "That wasn't so hard, was it?")
|
|
(slide-data :heading "The spectrum of flexibility"
|
|
:body "Hard-coded
|
|
Configurable / parametric
|
|
Partially programmable
|
|
Fully programmable")
|
|
(slide-data :heading "There are risks with
|
|
full programmability"
|
|
: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 "Questions to ask" :body "Can I express this problem with data?")
|
|
(slide-data :heading "Questions to ask" :body "Can I express this problem with data?
|
|
|
|
Can I author that data in a better way?")
|
|
(slide-data :heading "Questions to ask" :body "Can I express this problem with data?
|
|
|
|
Can I author that data in a better way?
|
|
|
|
How do I expect the problem, data,
|
|
and feature to grow?")
|
|
(slide-data :heading "Questions to ask" :body "Can I express this problem with data?
|
|
|
|
Can I author that data in a better way?
|
|
|
|
How do I expect the problem, data,
|
|
and feature to grow?
|
|
|
|
How are they actually growing?")
|
|
(slide-data :heading "Questions to ask" :body "Can I express this problem with data?
|
|
|
|
Can I author that data in a better way?
|
|
|
|
How do I expect the problem, data,
|
|
and feature to grow?
|
|
|
|
How are they actually growing?
|
|
|
|
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,
|
|
can be hard.")
|
|
(slide-data :heading "In conclusion"
|
|
:body "Doing this is not hard,
|
|
knowing when to do this, and to what extent,
|
|
can be hard.
|
|
|
|
That doesn't mean it shouldn't be done, but does
|
|
mean it should be done carefully.")
|
|
(slide-data :heading "Questions?"
|
|
:trigger "random-power-cycle"))
|
|
|