7

为了练习我的 OOP 知识,我正在用 javascript 制作 Pong 游戏(我知道,我知道,这就像在吉他店玩 Stairway to Heaven)。通过实现几种不同的技术,包括基于原型的 OOP 和函数式风格,我已经拥有了游戏的多个功能版本。但是,我这样做并不是为了获得功能性游戏,而是为了学习。

我正在使用 html5 画布和纯 ol' javascript,没有框架(好的,用于键盘捕获的一点 jQuery)。我有代表我的游戏的 Pong 对象。Pong 有一个ctx包含对canvas.getContext("2d")上下文的引用的属性。它还有一个player1,player2ball属性,用于保存你知道什么。当球和两名球员被实例化时,上下文被传递给他们的构造函数,以便他们也可以持有对上下文的引用以在他们的draw(ctx)方法中使用。Pong 有一个draw()方法可以使用setInterval(this.draw, 10). Pong 的 draw 方法会调用两个玩家和球的 draw 方法。

两名球员和球都具有上下文作为属性,这对我来说并不合适。他们不拥有上下文,因此它不应该是一个属性。然而,使用 javascript 和画布的本质似乎是这是最好的方法。在这种情况下,谁或什么应该拥有上下文?理想情况下,我根本不希望球员和球对象有平局对象。我觉得它们应该具有描述其几何形状和位置的属性,并且应该指定一个专门的对象将它们渲染到屏幕上。这样,如果将来我决定使用 <div> 而不是画布,我可以只更改渲染对象,而其他一切都将被遗忘。

我知道我正在制作一个比它需要的更复杂的 javascript Pong 游戏,但我想练习这些技术并真正了解 OOP 的概念,但每次我认为我已经破解了一个由我的“解决方案”创建的全新问题'呈现自己。

编辑:如果你对我的代码有一个八卦会有帮助,这里是一个(几乎)完全工作的版本:

library.js - http://mikemccabe.me/tests/pong.archive.14.06.11/library.js

pong.js - http://mikemccabe.me/tests/pong.archive.14.06.11/pong.js

试试看 - 出http://mikemccabe.me/tests/pong.archive.14.06.11/

4

4 回答 4

1

你让事情变得比它们的价值更复杂。

一个专门的对象应该负责将它们渲染到屏幕上......

当您有一项需要完成的任务时,说“一个对象的任务是”做这件事是很奇怪的。函数做事。对象封装数据。一个函数应该负责将它们呈现到屏幕上。

在这种情况下,谁或什么应该拥有上下文?

没有任何东西“拥有”上下文。或者,如果你愿意,画布拥有上下文,但我不知道你为什么要把上下文放在某个地方;我希望这比只是传递它更令人困惑。

编辑:看一眼你的代码,你已经让 Pong 闭包“拥有”(有一个引用,即)上下文,这似乎很合理。我真的不明白你用这种方法预计会出现什么问题。但是,我不同意您应该将它传递给Balletc 的构造函数。我认为将它传递给各种draw()方法要简单得多。

于 2011-06-15T19:26:44.580 回答
1

不是专门针对乒乓球的,而是这本在线书籍

http://eloquentjavascript.net/chapter8.html

有一个构建小游戏的例子。它略有不同,但它很好地展示了如何使用面向对象的原则。

您可以通过多种方式编写代码,并且很容易在设计模式上走得更远。与任何事情一样,使用适度。在使用新语言工作时,我一直使用 Nibbles/Snake 作为我的 goto 游戏。

于 2011-06-15T19:37:18.437 回答
1

这可能是应用 MVC(模型-视图-控制器)原则的绝佳案例。

您可以有一个模型来跟踪每个游戏元素的状态。这些可能是 Player、Paddle、Ball 等。然后,您可以拥有仅包含用于绘制当前状态的逻辑的渲染器(视图)。视图可以命名为 BallCanvasRenderer 和 PaddleCanvasRenderer。

由于视图会被很好地封装,让它保持对画布上下文的引用可能是有意义的,但您也可以在每次渲染时传入适当的上下文和模型。

控制器将负责响应游戏事件和更新模型。

请注意,此模式还为您提供了为任何类型的模型维护多个渲染器的选项。您还可以拥有输出文本、ASCII 艺术或 OpenGL 的渲染器。

于 2011-06-15T19:47:45.190 回答
1

我认为您对上下文的使用没有问题。为了实现允许渲染独立于技术的设计目标,您应该为您需要的渲染方法编写一个通用接口,并创建一个context用于实现该接口的对象。然后您可以替换该对象的另一个版本,例如,使其在 Internet Explorer <9 中工作。

在 Javascript 中,我认为使用范围来允许应用程序中的对象直接访问共享资源通常很方便。虽然这不是严格意义上的良好 OO 设计,但可以将其视为单例。例如:

var Pong = (function() {
   var Graphics, graphics, Ball, ball1, ball2, play;
   Graphics = function() {
      this.context = ...
   };
   graphics = new Graphics();
   Ball = function() {
     // do something with graphics
   };
   ball1 = new Ball();
   ball2 = new Ball();
   // ball1 and ball2 will both be able to access graphics

   play =function() {
       // play the game!
   };
   return {
       play: play
   }
}());

为了概括这一点,您可以只使Graphics对象具有通用方法而不是context直接提供访问,并且具有多个版本,根据浏览器实例化正确的版本。graphics与明确分配两者相比ball1ball2除了纯粹主义之外,没有任何缺点。当您处理数百个对象(例如,表示 DOM 元素)而不是仅仅几个时,好处就变得很大了。

于 2011-06-15T20:03:47.517 回答