paddy's endzone
This commit is contained in:
502
drills/html/paddys-endzone.html
Normal file
502
drills/html/paddys-endzone.html
Normal file
@@ -0,0 +1,502 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Paddy's Endzone Drill Animation</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-color: #1a1a1a;
|
||||||
|
--panel-color: #2c2c2c;
|
||||||
|
--accent-color: #4CAF50;
|
||||||
|
--text-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 650px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
background-color: #2e7d32;
|
||||||
|
border: 3px solid #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
background-color: var(--panel-color);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 10px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: #444;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover { background: #555; }
|
||||||
|
button:active { transform: translateY(1px); }
|
||||||
|
|
||||||
|
button.primary { background: var(--accent-color); }
|
||||||
|
button.primary:hover { background: #45a049; }
|
||||||
|
|
||||||
|
.speed-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #444;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
text-align: center;
|
||||||
|
min-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stepDescription {
|
||||||
|
font-style: italic;
|
||||||
|
color: #ccc;
|
||||||
|
margin-top: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h2 style="margin: 0; text-align: center;">Paddy's Endzone Drill</h2>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<strong id="stepTitle">Ready to start</strong>
|
||||||
|
<span id="stepDescription">Click Play or Next Step</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas id="drillCanvas" width="600" height="700"></canvas>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<div class="button-row">
|
||||||
|
<button id="prevBtn">Prev Step</button>
|
||||||
|
<button id="playBtn" class="primary">Play</button>
|
||||||
|
<button id="nextBtn">Next Step</button>
|
||||||
|
<button id="resetBtn">Reset</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="speed-row">
|
||||||
|
<label for="speedSelect">Animation Speed:</label>
|
||||||
|
<select id="speedSelect">
|
||||||
|
<option value="1">Normal</option>
|
||||||
|
<option value="2" selected>Faster</option>
|
||||||
|
<option value="4">High Speed</option>
|
||||||
|
<option value="8">Insane (No Skips)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="legend">
|
||||||
|
<span>🟡 Disc</span>
|
||||||
|
<span>⚪ Player</span>
|
||||||
|
<span>🟢 Endzone</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* FIELD PROPORTIONS (1m = 16.2px)
|
||||||
|
* Realistic Width: 37m = 600px
|
||||||
|
* Endzone Depth: 18m = 292px
|
||||||
|
* Total view: ~43m height
|
||||||
|
*/
|
||||||
|
|
||||||
|
const canvas = document.getElementById('drillCanvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const W = 600;
|
||||||
|
const SCALE = W / 37; // px per meter
|
||||||
|
const EZ_DEPTH = 18 * SCALE;
|
||||||
|
const BACK_LINE = 50; // top padding
|
||||||
|
const GOAL_LINE = BACK_LINE + EZ_DEPTH;
|
||||||
|
const SIDELINE_3M = 3 * SCALE;
|
||||||
|
const MID_X = W / 2;
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
const COLORS = {
|
||||||
|
disc: '#ffeb3b',
|
||||||
|
player: '#ffffff',
|
||||||
|
playerText: '#000000',
|
||||||
|
goalHandler: '#ff9800'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initial Player Data
|
||||||
|
// Back stack: H2(closest back), H4, H6
|
||||||
|
// Front stack: H3(closest handler), H5, H7
|
||||||
|
const defaultBackY = [BACK_LINE + 15, BACK_LINE + 55, BACK_LINE + 95];
|
||||||
|
const defaultFrontY = [GOAL_LINE - 95, GOAL_LINE - 55, GOAL_LINE - 15];
|
||||||
|
|
||||||
|
let players = {
|
||||||
|
H1: { x: 10 * SCALE, y: GOAL_LINE + (15 * SCALE), label: 'H1' },
|
||||||
|
H2: { x: MID_X, y: defaultBackY[0], label: 'H2' },
|
||||||
|
H4: { x: MID_X, y: defaultBackY[1], label: 'H4' },
|
||||||
|
H6: { x: MID_X, y: defaultBackY[2], label: 'H6' },
|
||||||
|
H3: { x: MID_X, y: defaultFrontY[2], label: 'H3' },
|
||||||
|
H5: { x: MID_X, y: defaultFrontY[1], label: 'H5' },
|
||||||
|
H7: { x: MID_X, y: defaultFrontY[0], label: 'H7' }
|
||||||
|
};
|
||||||
|
|
||||||
|
let disc = { x: players.H1.x, y: players.H1.y, attached: 'H1' };
|
||||||
|
|
||||||
|
let currentStep = 0;
|
||||||
|
let progress = 0;
|
||||||
|
let isPlaying = false;
|
||||||
|
let lastTimestamp = 0;
|
||||||
|
|
||||||
|
// Drill Step Definitions
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: "Step 1: The Initial Look",
|
||||||
|
desc: "H2 cuts across. H1 throws a curved around-forehand.",
|
||||||
|
duration: 1.5,
|
||||||
|
animate: (t) => {
|
||||||
|
// H2 cut parallel to backline
|
||||||
|
players.H2.x = lerp(MID_X, W - SIDELINE_3M, t);
|
||||||
|
|
||||||
|
// Pass flight (Curved)
|
||||||
|
if (t > 0.1) {
|
||||||
|
const pt = (t - 0.1) / 0.9;
|
||||||
|
disc.attached = null;
|
||||||
|
const curve = Math.sin(pt * Math.PI) * 120; // Around curve
|
||||||
|
disc.x = lerp(players.H1.x, W - SIDELINE_3M, pt) + curve;
|
||||||
|
disc.y = lerp(players.H1.y, defaultBackY[0], pt);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd: () => { disc.attached = 'H2'; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 2: Handler Rotation",
|
||||||
|
desc: "H1 joins back stack. Stack shifts to maintain original backline depth.",
|
||||||
|
duration: 1.2,
|
||||||
|
animate: (t) => {
|
||||||
|
// H1 moves to front of back stack
|
||||||
|
players.H1.x = lerp(10 * SCALE, MID_X, t);
|
||||||
|
players.H1.y = lerp(GOAL_LINE + (15 * SCALE), defaultBackY[2], t);
|
||||||
|
// Shift others
|
||||||
|
players.H4.y = lerp(defaultBackY[1], defaultBackY[0], t);
|
||||||
|
players.H6.y = lerp(defaultBackY[2], defaultBackY[1], t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 3: Reset Look",
|
||||||
|
desc: "H3 cuts out to opposite handler spot. Gets pass from H2.",
|
||||||
|
duration: 1.3,
|
||||||
|
animate: (t) => {
|
||||||
|
const targetX = W - (10 * SCALE);
|
||||||
|
const targetY = GOAL_LINE + (15 * SCALE);
|
||||||
|
players.H3.x = lerp(MID_X, targetX, t);
|
||||||
|
players.H3.y = lerp(defaultFrontY[2], targetY, t);
|
||||||
|
|
||||||
|
if (t > 0.1) {
|
||||||
|
const pt = (t - 0.1) / 0.9;
|
||||||
|
disc.attached = null;
|
||||||
|
disc.x = lerp(W - SIDELINE_3M, targetX, pt);
|
||||||
|
disc.y = lerp(defaultBackY[0], targetY, pt);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd: () => { disc.attached = 'H3'; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 4: Front Stack Reset",
|
||||||
|
desc: "H2 moves to back of front stack. Stack shifts forward.",
|
||||||
|
duration: 1.2,
|
||||||
|
animate: (t) => {
|
||||||
|
players.H2.x = lerp(W - SIDELINE_3M, MID_X, t);
|
||||||
|
players.H2.y = lerp(defaultBackY[0], defaultFrontY[0], t);
|
||||||
|
// Shift front stack to fill
|
||||||
|
players.H5.y = lerp(defaultFrontY[1], defaultFrontY[2], t);
|
||||||
|
players.H7.y = lerp(defaultFrontY[0], defaultFrontY[1], t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 5: Breakside Look",
|
||||||
|
desc: "H4 cuts opposite. H3 throws curved around-backhand.",
|
||||||
|
duration: 1.5,
|
||||||
|
animate: (t) => {
|
||||||
|
const h3X = W - (10 * SCALE);
|
||||||
|
const h3Y = GOAL_LINE + (15 * SCALE);
|
||||||
|
|
||||||
|
players.H4.x = lerp(MID_X, SIDELINE_3M, t);
|
||||||
|
|
||||||
|
if (t > 0.1) {
|
||||||
|
const pt = (t - 0.1) / 0.9;
|
||||||
|
disc.attached = null;
|
||||||
|
const curve = Math.sin(pt * Math.PI) * -120;
|
||||||
|
disc.x = lerp(h3X, SIDELINE_3M, pt) + curve;
|
||||||
|
disc.y = lerp(h3Y, defaultBackY[0], pt);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd: () => { disc.attached = 'H4'; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 6: Secondary Handler Rotation",
|
||||||
|
desc: "H3 joins back stack. Back stack shifts.",
|
||||||
|
duration: 1.2,
|
||||||
|
animate: (t) => {
|
||||||
|
const h3X = W - (10 * SCALE);
|
||||||
|
const h3Y = GOAL_LINE + (15 * SCALE);
|
||||||
|
players.H3.x = lerp(h3X, MID_X, t);
|
||||||
|
players.H3.y = lerp(h3Y, defaultBackY[2], t);
|
||||||
|
// Stack shift
|
||||||
|
players.H1.y = lerp(defaultBackY[2], defaultBackY[1], t);
|
||||||
|
players.H6.y = lerp(defaultBackY[1], defaultBackY[0], t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Step 7: Final Reset",
|
||||||
|
desc: "H5 cuts out. H4 joins front stack. H5 receives pass.",
|
||||||
|
duration: 1.5,
|
||||||
|
animate: (t) => {
|
||||||
|
// H5 cut
|
||||||
|
players.H5.x = lerp(MID_X, 10 * SCALE, t);
|
||||||
|
players.H5.y = lerp(defaultFrontY[2], GOAL_LINE + (15 * SCALE), t);
|
||||||
|
// H4 reset
|
||||||
|
players.H4.x = lerp(SIDELINE_3M, MID_X, t);
|
||||||
|
players.H4.y = lerp(defaultBackY[0], defaultFrontY[0], t);
|
||||||
|
// Stack reset
|
||||||
|
players.H7.y = lerp(defaultFrontY[1], defaultFrontY[2], t);
|
||||||
|
players.H2.y = lerp(defaultFrontY[0], defaultFrontY[1], t);
|
||||||
|
|
||||||
|
if (t > 0.1) {
|
||||||
|
const pt = (t - 0.1) / 0.9;
|
||||||
|
disc.attached = null;
|
||||||
|
disc.x = lerp(SIDELINE_3M, 10 * SCALE, pt);
|
||||||
|
disc.y = lerp(defaultBackY[0], GOAL_LINE + (15 * SCALE), pt);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd: () => { disc.attached = 'H5'; }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// Helper Functions
|
||||||
|
function lerp(start, end, t) {
|
||||||
|
return start * (1 - t) + end * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawField() {
|
||||||
|
ctx.clearRect(0, 0, W, canvas.height);
|
||||||
|
|
||||||
|
// Goal and back lines
|
||||||
|
ctx.strokeStyle = "white";
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
|
||||||
|
// Sidelines
|
||||||
|
ctx.strokeRect(0, -10, W, canvas.height + 20);
|
||||||
|
|
||||||
|
// Goal line
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, GOAL_LINE); ctx.lineTo(W, GOAL_LINE);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Back line
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, BACK_LINE); ctx.lineTo(W, BACK_LINE);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Shaded Endzone
|
||||||
|
ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
|
||||||
|
ctx.fillRect(0, BACK_LINE, W, EZ_DEPTH);
|
||||||
|
|
||||||
|
// Players
|
||||||
|
for (const key in players) {
|
||||||
|
const p = players[key];
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(p.x, p.y, 10, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = COLORS.player;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.strokeStyle = "#000";
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.fillStyle = COLORS.playerText;
|
||||||
|
ctx.font = "bold 10px Arial";
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
ctx.fillText(p.label, p.x, p.y + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disc
|
||||||
|
const dX = disc.attached ? players[disc.attached].x + 8 : disc.x;
|
||||||
|
const dY = disc.attached ? players[disc.attached].y - 8 : disc.y;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(dX, dY, 5, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = COLORS.disc;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.strokeStyle = "orange";
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(timestamp) {
|
||||||
|
if (!lastTimestamp) lastTimestamp = timestamp;
|
||||||
|
const delta = (timestamp - lastTimestamp) / 1000;
|
||||||
|
lastTimestamp = timestamp;
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
const speedMultiplier = parseFloat(document.getElementById('speedSelect').value);
|
||||||
|
const step = steps[currentStep];
|
||||||
|
|
||||||
|
progress += (delta / step.duration) * speedMultiplier;
|
||||||
|
|
||||||
|
if (progress >= 1) {
|
||||||
|
progress = 1;
|
||||||
|
step.animate(1);
|
||||||
|
if (step.onEnd) step.onEnd();
|
||||||
|
|
||||||
|
if (currentStep < steps.length - 1) {
|
||||||
|
currentStep++;
|
||||||
|
progress = 0;
|
||||||
|
} else {
|
||||||
|
isPlaying = false;
|
||||||
|
document.getElementById('playBtn').textContent = "Restart";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
step.animate(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawField();
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUI() {
|
||||||
|
const step = steps[currentStep];
|
||||||
|
document.getElementById('stepTitle').textContent = step.title;
|
||||||
|
document.getElementById('stepDescription').textContent = step.desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetDrill() {
|
||||||
|
isPlaying = false;
|
||||||
|
currentStep = 0;
|
||||||
|
progress = 0;
|
||||||
|
|
||||||
|
// Deep clone initial state
|
||||||
|
players.H1 = { x: 10 * SCALE, y: GOAL_LINE + (15 * SCALE), label: 'H1' };
|
||||||
|
players.H2 = { x: MID_X, y: defaultBackY[0], label: 'H2' };
|
||||||
|
players.H4 = { x: MID_X, y: defaultBackY[1], label: 'H4' };
|
||||||
|
players.H6 = { x: MID_X, y: defaultBackY[2], label: 'H6' };
|
||||||
|
players.H3 = { x: MID_X, y: defaultFrontY[2], label: 'H3' };
|
||||||
|
players.H5 = { x: MID_X, y: defaultFrontY[1], label: 'H5' };
|
||||||
|
players.H7 = { x: MID_X, y: defaultFrontY[0], label: 'H7' };
|
||||||
|
|
||||||
|
disc = { x: players.H1.x, y: players.H1.y, attached: 'H1' };
|
||||||
|
|
||||||
|
document.getElementById('playBtn').textContent = "Play";
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control Listeners
|
||||||
|
document.getElementById('playBtn').addEventListener('click', () => {
|
||||||
|
if (currentStep === steps.length - 1 && progress === 1) {
|
||||||
|
resetDrill();
|
||||||
|
}
|
||||||
|
isPlaying = !isPlaying;
|
||||||
|
document.getElementById('playBtn').textContent = isPlaying ? "Pause" : "Play";
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('nextBtn').addEventListener('click', () => {
|
||||||
|
isPlaying = false;
|
||||||
|
document.getElementById('playBtn').textContent = "Play";
|
||||||
|
|
||||||
|
// If mid-progress, finish current step
|
||||||
|
if (progress < 1) {
|
||||||
|
progress = 1;
|
||||||
|
steps[currentStep].animate(1);
|
||||||
|
if (steps[currentStep].onEnd) steps[currentStep].onEnd();
|
||||||
|
} else if (currentStep < steps.length - 1) {
|
||||||
|
currentStep++;
|
||||||
|
progress = 1;
|
||||||
|
steps[currentStep].animate(1);
|
||||||
|
if (steps[currentStep].onEnd) steps[currentStep].onEnd();
|
||||||
|
}
|
||||||
|
updateUI();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('prevBtn').addEventListener('click', () => {
|
||||||
|
isPlaying = false;
|
||||||
|
document.getElementById('playBtn').textContent = "Play";
|
||||||
|
|
||||||
|
if (currentStep > 0) {
|
||||||
|
currentStep--;
|
||||||
|
progress = 1;
|
||||||
|
// Logic to rewind visual state is complex in simple lerp engines
|
||||||
|
// Best practice for this simple engine is to reset and fast-forward
|
||||||
|
const targetStep = currentStep;
|
||||||
|
resetDrill();
|
||||||
|
for(let i=0; i <= targetStep; i++) {
|
||||||
|
currentStep = i;
|
||||||
|
progress = 1;
|
||||||
|
steps[i].animate(1);
|
||||||
|
if(steps[i].onEnd) steps[i].onEnd();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resetDrill();
|
||||||
|
}
|
||||||
|
updateUI();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('resetBtn').addEventListener('click', resetDrill);
|
||||||
|
|
||||||
|
// Start
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
drills/prompts.md
Normal file
25
drills/prompts.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Can you create ultimate frisbee drill animation for me?
|
||||||
|
|
||||||
|
```
|
||||||
|
Drill: Paddy's endzone
|
||||||
|
Players: 2 short vertical stacks in the endzone separated by slightly bigger space in the middle, players in the stack are close together, one at the back and other on the front each of them moving independently on the other, one player in front of the endzone, about 10-20 metres away and 10 metres from the sideline
|
||||||
|
Field:
|
||||||
|
- Field has lines as ultimate frisbee field would have
|
||||||
|
- make proportions of the endzone and rest of the field realistic
|
||||||
|
- Field takes up whole width of the canvas
|
||||||
|
- It is enough to have only half of the field in the picture
|
||||||
|
Setup: H1 at the disc, H2,H4,H6 in the back stack - starting with H2 closest to back endzone libe, H3, H5, H7 in the front stack - starting with H3 closest to player with disc, whole front stack is fully in the endzone
|
||||||
|
Extra details:
|
||||||
|
- when you are showing pass in the animation make it at least in 3 frames
|
||||||
|
- make default speed faster and faster even faster, possibly add 2 more speed options, faster speed should not skip frames, it just should move quicker from one to another
|
||||||
|
- make sure players do not cut out of bounds
|
||||||
|
- allow to go through animation one step at a time
|
||||||
|
Steps:
|
||||||
|
1. H2 cuts to the oposite side of H1 with cut parallel to the back line and H1 throws around forehand over both stacks and hits H2 about 3 metres off the sideline curving to the receiver
|
||||||
|
2. H1 moves into position closest to the front of end zone of the back stack, whole back stack moves so that player closest to the back of endzone is on the same position last player was on the start of the drill
|
||||||
|
3. H3 cuts out of the endzone to similar place where H1 was, but on the other side and gets pass from H2
|
||||||
|
4. H2 moves to the back of the front stack which moves in the way it now starts on the same spot as when we begun the drill
|
||||||
|
5. H4 cuts in the same way H2 cut in the step 1, only to the oposite side and H3 throws around backhand both stacks and hits H4 about 3 metres off the sideline curving to the receiver
|
||||||
|
7. H3 moves into position closest to the front of end zone of the back stack, whole back stack moves so that player closest to the back of endzone is on the same position last player was on the start of the drill
|
||||||
|
6. H5 cuts out of the endzone to place where H1 was, gets pass from H4, H4 moves to the back of the front stack
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user