কেস স্টাডি - Google I/O 2013 পরীক্ষা৷

টমাস রেনল্ডস
টমাস রেনল্ডস

ভূমিকা

কনফারেন্স রেজিস্ট্রেশন খোলার আগে Google I/O 2013 ওয়েবসাইটে বিকাশকারীর আগ্রহ তৈরি করতে, আমরা স্পর্শ ইন্টারঅ্যাকশন, জেনারেটিভ অডিও এবং আবিষ্কারের আনন্দের উপর ফোকাস করে মোবাইল-প্রথম পরীক্ষা এবং গেমগুলির একটি সিরিজ তৈরি করেছি। কোডের সম্ভাবনা এবং খেলার শক্তি দ্বারা অনুপ্রাণিত হয়ে, আপনি যখন নতুন I/O লোগোতে ট্যাপ করেন তখন এই ইন্টারেক্টিভ অভিজ্ঞতাটি "I" এবং "O" এর সাধারণ ধ্বনি দিয়ে শুরু হয়।

জৈব গতি

আমরা I এবং O অ্যানিমেশনগুলিকে একটি নড়বড়ে, জৈব প্রভাবে প্রয়োগ করার সিদ্ধান্ত নিয়েছি যা প্রায়শই HTML5 ইন্টারঅ্যাকশনগুলিতে দেখা যায় না। এটিকে মজাদার এবং প্রতিক্রিয়াশীল বোধ করতে বিকল্পগুলিতে ডায়াল করা একটু সময় নিয়েছে।

বাউন্সি ফিজিক্স কোডের উদাহরণ

এই প্রভাবটি সম্পন্ন করার জন্য, আমরা দুটি আকারের প্রান্তের প্রতিনিধিত্বকারী পয়েন্টগুলির একটি সিরিজে একটি সাধারণ পদার্থবিদ্যা সিমুলেশন ব্যবহার করেছি। যখন যে কোনও আকারে ট্যাপ করা হয়, ট্যাপের অবস্থান থেকে সমস্ত পয়েন্ট ত্বরান্বিত হয়। তারা ফিরে টেনে আনার আগে প্রসারিত এবং দূরে.

ইনস্ট্যান্টেশনে, প্রতিটি পয়েন্ট একটি এলোমেলো ত্বরণ পরিমাণ পায় এবং "বাউন্সিনেস" রিবাউন্ড করে যাতে তারা সমানভাবে অ্যানিমেট না হয়, আপনি এই কোডে দেখতে পাচ্ছেন:

this.paperO_['vectors'] = [];

// Add an array of vector points and properties to the object.
for (var i = 0; i < this.paperO_['segments'].length; i++) {
  var point = this.paperO_['segments'][i]['point']['clone']();
  point = point['subtract'](this.oCenter);

  point['velocity'] = 0;
  point['acceleration'] = Math.random() * 5 + 10;
  point['bounce'] = Math.random() * 0.1 + 1.05;

  this.paperO_['vectors'].push(point);
}

তারপরে, ট্যাপ করা হলে, এখানে কোডটি ব্যবহার করে ট্যাপের অবস্থান থেকে বাইরের দিকে ত্বরান্বিত হয়:

for (var i = 0; i < path['vectors'].length; i++) {
  var point = path['vectors'][i];
  var vector;
  var distance;

  if (path === this.paperO_) {
    vector = point['add'](this.oCenter);
    vector = vector['subtract'](clickPoint);
    distance = Math.max(0, this.oRad - vector['length']);
  } else {
    vector = point['add'](this.iCenter);
    vector = vector['subtract'](clickPoint);
    distance = Math.max(0, this.iWidth - vector['length']);
  }

  point['length'] += Math.max(distance, 20);
  point['velocity'] += speed;
}

অবশেষে, প্রতিটি কণা প্রতিটি ফ্রেমে হ্রাস পায় এবং কোডে এই পদ্ধতির সাথে ধীরে ধীরে ভারসাম্য ফিরে আসে:

for (var i = 0; i < path['segments'].length; i++) {
  var point = path['vectors'][i];
  var tempPoint = new paper['Point'](this.iX, this.iY);

  if (path === this.paperO_) {
    point['velocity'] = ((this.oRad - point['length']) /
      point['acceleration'] + point['velocity']) / point['bounce'];
  } else {
    point['velocity'] = ((tempPoint['getDistance'](this.iCenter) -
      point['length']) / point['acceleration'] + point['velocity']) /
      point['bounce'];
  }

  point['length'] = Math.max(0, point['length'] + point['velocity']);
}

অর্গানিক মোশন ডেমো

আপনার সাথে খেলার জন্য এখানে I/O হোম মোড রয়েছে। আমরা এই বাস্তবায়নে অতিরিক্ত বিকল্পগুলির একটি গুচ্ছও প্রকাশ করেছি। আপনি যদি "শো পয়েন্ট" চালু করেন তবে আপনি পৃথক পয়েন্টগুলি দেখতে পাবেন যা পদার্থবিজ্ঞানের সিমুলেশন এবং শক্তিগুলি কাজ করছে।

রিস্কিনিং

একবার আমরা হোম মোড গতিতে খুশি হয়েছিলাম, আমরা দুটি বিপরীতমুখী মোডের জন্য একই প্রভাব ব্যবহার করতে চেয়েছিলাম: আটবিট এবং অ্যাসিআই।

এই রিস্কিনিং সম্পন্ন করার জন্য, আমরা হোম মোড থেকে একই ক্যানভাস ব্যবহার করেছি এবং দুটি প্রভাবের প্রতিটি তৈরি করতে পিক্সেল ডেটা ব্যবহার করেছি। এই পদ্ধতিটি একটি OpenGL ফ্র্যাগমেন্ট শেডারের স্মরণ করিয়ে দেয় যেখানে দৃশ্যের প্রতিটি পিক্সেল পরিদর্শন করা হয় এবং ম্যানিপুলেট করা হয়। এর মধ্যে আরো ডুব দেওয়া যাক.

ক্যানভাস "শেডার" কোডের উদাহরণ

একটি ক্যানভাসের পিক্সেলগুলি getImageData পদ্ধতি ব্যবহার করে পড়া যেতে পারে। প্রত্যাবর্তিত অ্যারেতে পিক্সেল প্রতি 4টি মান রয়েছে যা প্রতিটি পিক্সেল RGBA মানকে উপস্থাপন করে। এই পিক্সেলগুলি একটি বৃহদায়তন অ্যারের মতো কাঠামোতে একত্রিত হয়। উদাহরণস্বরূপ, একটি 2x2 ক্যানভাসের ইমেজডেটা অ্যারেতে 4 পিক্সেল এবং 16টি এন্ট্রি থাকবে।

আমাদের ক্যানভাস সম্পূর্ণ স্ক্রীন, তাই যদি আমরা মনে করি স্ক্রীনটি 1024x768 (একটি iPad এর মত), তাহলে অ্যারেটিতে 3,145,728 এন্ট্রি রয়েছে৷ কারণ এটি একটি অ্যানিমেশন, এই সম্পূর্ণ অ্যারেটি সেকেন্ডে 60 বার আপডেট হয়। আধুনিক জাভাস্ক্রিপ্ট ইঞ্জিনগুলি ফ্রেমরেটকে সামঞ্জস্যপূর্ণ রাখতে এত দ্রুত ডেটা লুপিং এবং কাজ করতে পারে। (টিপ: ডেভেলপার কনসোলে সেই ডেটা লগ করার চেষ্টা করবেন না, কারণ এটি আপনার ব্রাউজারকে ক্রল করতে ধীর করে দেবে বা সম্পূর্ণরূপে ক্র্যাশ করবে।)

আমাদের এইটবিট মোড কীভাবে হোম মোড ক্যানভাস পড়ে এবং একটি ব্লকিয়ার প্রভাব পেতে পিক্সেলগুলিকে উড়িয়ে দেয় তা এখানে রয়েছে:

var pixelData = pctx.getImageData(0, 0, sourceCanvas.width, sourceCanvas.height);

// tctx is the Target Context for the output Canvas element
tctx.clearRect(0, 0, targetCanvas.width + 1, targetCanvas.height + 1);

var size = ~~(this.width_ * 0.0625);

if (this.height_ * 6 < this.width_) {
 size /= 8;
}

var increment = Math.min(Math.round(size * 80) / 4, 980);

for (i = 0; i < pixelData.data.length; i += increment) {
  if (pixelData.data[i + 3] !== 0) {
    var r = pixelData.data[i];
    var g = pixelData.data[i + 1];
    var b = pixelData.data[i + 2];
    var pixel = Math.ceil(i / 4);
    var x = pixel % this.width_;
    var y = Math.floor(pixel / this.width_);

    var color = 'rgba(' + r + ', ' + g + ', ' + b + ', 1)';

    tctx.fillStyle = color;

    /**
     * The ~~ operator is a micro-optimization to round a number down
     * without using Math.floor. Math.floor has to look up the prototype
     * tree on every invocation, but ~~ is a direct bitwise operation.
     */
    tctx.fillRect(x - ~~(size / 2), y - ~~(size / 2), size, size);
  }
}

এইটবিট শেডার ডেমো

নীচে, আমরা Eightbit ওভারলে সরিয়ে ফেলি এবং নীচে আসল অ্যানিমেশন দেখতে পাই। "কিল স্ক্রিন" বিকল্পটি আপনাকে একটি অদ্ভুত প্রভাব দেখাবে যা আমরা ভুলভাবে উৎস পিক্সেলের নমুনা দিয়ে হোঁচট খেয়েছি। আমরা এটিকে "প্রতিক্রিয়াশীল" ইস্টার ডিম হিসাবে ব্যবহার করে শেষ করেছি যখন Eightbit মোডের আকার পরিবর্তন করে অসম্ভাব্য আকৃতির অনুপাত করা হয়৷ শুভ দুর্ঘটনা!

ক্যানভাস কম্পোজিং

এটি বেশ আশ্চর্যজনক যে আপনি একাধিক রেন্ডার পদক্ষেপ এবং মুখোশ একত্রিত করে সম্পন্ন করতে পারেন। আমরা একটি 2D মেটাবল তৈরি করেছি যার জন্য প্রতিটি বলের নিজস্ব রেডিয়াল গ্রেডিয়েন্ট থাকা প্রয়োজন এবং সেই গ্রেডিয়েন্টগুলিকে একসাথে মিশ্রিত করা হবে যেখানে বলগুলি ওভারল্যাপ হয়৷ (আপনি নীচের ডেমোতে এটি দেখতে পারেন।)

এটি সম্পন্ন করার জন্য, আমরা দুটি পৃথক ক্যানভাস ব্যবহার করেছি। প্রথম ক্যানভাস গণনা করে এবং মেটাবল আকৃতি আঁকে। একটি দ্বিতীয় ক্যানভাস প্রতিটি বলের অবস্থানে রেডিয়াল গ্রেডিয়েন্ট আঁকে। তারপর আকৃতি গ্রেডিয়েন্টগুলিকে মাস্ক করে এবং আমরা চূড়ান্ত আউটপুট রেন্ডার করি।

কম্পোজিং কোডের উদাহরণ

এখানে কোড যা সবকিছু ঘটায়:

// Loop through every ball and draw it and its gradient.
for (var i = 0; i < this.ballCount_; i++) {
  var target = this.world_.particles[i];

  // Set the size of the ball radial gradients.
  this.gradSize_ = target.radius * 4;

  this.gctx_.translate(target.pos.x - this.gradSize_,
    target.pos.y - this.gradSize_);

  var radGrad = this.gctx_.createRadialGradient(this.gradSize_,
    this.gradSize_, 0, this.gradSize_, this.gradSize_, this.gradSize_);

  radGrad.addColorStop(0, target['color'] + '1)');
  radGrad.addColorStop(1, target['color'] + '0)');

  this.gctx_.fillStyle = radGrad;
  this.gctx_.fillRect(0, 0, this.gradSize_ * 4, this.gradSize_ * 4);
};

তারপর, মাস্কিং এবং আঁকার জন্য ক্যানভাস সেট আপ করুন:

// Make the ball canvas the source of the mask.
this.pctx_.globalCompositeOperation = 'source-atop';

// Draw the ball canvas onto the gradient canvas to complete the mask.
this.pctx_.drawImage(this.gcanvas_, 0, 0);
this.ctx_.drawImage(this.paperCanvas_, 0, 0);

উপসংহার

আমরা যে বিভিন্ন কৌশল ব্যবহার করতে পেরেছি এবং যে প্রযুক্তিগুলি আমরা প্রয়োগ করেছি (যেমন ক্যানভাস, এসভিজি, সিএসএস অ্যানিমেশন, জেএস অ্যানিমেশন, ওয়েব অডিও, ইত্যাদি) প্রকল্পটিকে বিকাশের জন্য অবিশ্বাস্যভাবে মজাদার করেছে৷

আপনি এখানে যা দেখছেন তার চেয়েও অন্বেষণ করার আরও অনেক কিছু আছে। I/O লোগোতে ট্যাপ করতে থাকুন এবং সঠিক সিকোয়েন্সগুলি আরও মিনি-পরীক্ষা, গেমস, ট্রিপি ভিজ্যুয়াল এবং সম্ভবত কিছু প্রাতঃরাশের খাবার আনলক করবে। আমরা আপনাকে সেরা অভিজ্ঞতার জন্য আপনার স্মার্টফোন বা ট্যাবলেটে এটি চেষ্টা করার পরামর্শ দিই।

আপনার শুরু করার জন্য এখানে একটি সংমিশ্রণ রয়েছে: OIIIIIII। এখনই চেষ্টা করুন: google.com/io

মুক্ত উৎস

আমরা আমাদের কোড Apache 2.0 লাইসেন্স ওপেন সোর্স করেছি। আপনি এটি আমাদের Github-এ খুঁজে পেতে পারেন: http://github.com/Instrument/google-io-2013

ক্রেডিট

বিকাশকারীরা:

  • টমাস রেনল্ডস
  • ব্রায়ান হেফটার
  • স্টেফানি হ্যাচার
  • পল ফার্নিং

ডিজাইনার:

  • ড্যান শেকটার
  • সেজ ব্রাউন
  • কাইল বেক

প্রযোজক:

  • অ্যামি প্যাসকেল
  • আন্দ্রেয়া নেলসন