Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #37835

Re: Tetris rough draft (very rough)

Newsgroups comp.lang.javascript
Date 2019-11-22 09:07 -0800
References <19746231-7b69-47b2-b5c3-21d97a7227de@googlegroups.com>
Message-ID <d3485732-2d16-4ea4-8ca2-9e3600bf4067@googlegroups.com> (permalink)
Subject Re: Tetris rough draft (very rough)
From Julio Di Egidio <julio@diegidio.name>

Show all headers | View raw


On Sunday, 17 November 2019 01:13:35 UTC+1, luserdroog  wrote:
> Many thanks for the suggestions to my questions about
> my game loop. I have it a little more fleshed out now.
> But there are a whole host of little problems, not least
> of which is the sluggish response. I'm also having 
> difficulty getting the pieces to rotate around their
> center points. 
> 
> I chose to represent a tetromino piece as a 4x4 bitmap 
> in an integer expressed in hexadecimal. This worked great 
> on paper, but the logic to manipulate them is getting a 
> little cumbersome and confusing.
> 
> So, here's my mess. Any suggestions for improvement welcome.

Few sparse comments/suggestions:

> class Tet {

The main problem is that you have not partitioned responsibilities correctly
(not enough).  The Tet "class" is your game logic (call it Tetris, with possibly
a TetrisPiece "class" to represent the single piece), and it should be in charge
of everything related to the logic of the game, not just positions and allowed
moves, but also the logic for initial as well as end-game positions (logic for
winning/losing matches), how many points one scores, and similar.

OTOH, any rendering logic should be in a View "class", in particular how to map
game board and pieces from their own (game-specific) representation and cords
(and you would use unit coords and distances there: e.g. offsets are by 1, not
by 10, which is a detail of the rendering and not necessarily a fixed one) to
pixels on a canvas or other rendering target of any arbitrary kind and size.

>     get width(){
> 	return {
> 	    0x33: 2,  0x63: 3, 0x132: 2,  0xf: 4, 0x1111: 1,
> 	    0x47: 3, 0x113: 2, 0x71: 3, 0x322: 2,
> 	    0x74: 3, 0x223: 2, 0x17: 3, 0x311: 2,
> 	    0x27: 3, 0x131: 2, 0x72: 3, 0x232: 2
> 	}[ this.tet ];
>     }

That and similar are clever but highly inefficient.  Use a constant data
structure in the outer scope to hold that data (for one thing, you are now
recreating it at each and every function invocation), and access that where you
need.  Moreover, better use a single data structure where to each key (to each
piece type) you associate all the needed info, from how big it is to how it
rotates.  And better get also rid of those "adjust" functions as separate
functions: that logic should be encapsulated directly into the game board
logic itself.  I mean, something like (just an initial sketch to give an
overall idea, the details might very well end up being different):

const TetrisPieceSpec = {
  0x33: {
    width: 2,
    height: 2,
    rotLeft: { key: 0x33, offsetX: 0, offsetY: 0 },
	...
  },
  ...
}

function TetrisPiece(key, x, y) {
  this.key = key;
  this.x = x;
  this.y = y;
  
  this.rotateLeft = function () {
    var left = TetrisPieceSpec[this.key].rotLeft;
	
	var leftX = this.x + left.offsetX;
	var leftY = this.y + left.offsetY;
	
    return new TetrisPiece(left.key, leftX, leftY);
  };
  
  ...
}

function Tetris(onUpdate) {  // a callback as the simpliest notification
                             // mechanism: of course better can be done...
  this.board = ...create pieces...;
  this.state = TETRIS_STATE.BOOTING;  // then READY, STARTED, ENDED, or similar
  ...
  this.start = function () { ...; onUpdate(); };
  this.move = function (move) { ...; onUpdate(); };
  ...
  this.canStart = function () { ... };
  this.canMove = function (move) { ... };
  ...
}

function TetrisView(Tetris) {  // Tetris (the "game") is directly the model: I
                               // am passing the constructor here due to having 
                               // to pass a callback to it, but, as said, better
                               // can be done, and I do not mean custom events
                               // but rather observable interfaces and data
                               // binding engines: look up Knockout.js...
  var game = new Tetris(onUpdate);
  
  function onUpdate() {
    ...re-render...
  }
  
  this.start = function () { if game.canStart() { game.start(); } };
  ...
}

> var lastRender = 0;
> function loop( timestamp ){
>     var progress = timestamp - lastRender;
>     if( progress > 100 ){
> 	update( progress );
> 	lastRender = timestamp;
>     }
>     window.requestAnimationFrame( loop );
> }
> window.requestAnimationFrame( loop );

BTW, isn't that actually keeping your CPU pretty busy all the time?
That is just not the way you implement an animation loop in any language,
all the more so in JS where Thread.sleep and similar do not even make sense...

Julio

Back to comp.lang.javascript | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Tetris rough draft (very rough) luserdroog <luser.droog@gmail.com> - 2019-11-16 16:13 -0800
  Re: Tetris rough draft (very rough) luserdroog <luser.droog@gmail.com> - 2019-11-16 21:53 -0800
  Re: Tetris rough draft (very rough) Julio Di Egidio <julio@diegidio.name> - 2019-11-22 09:07 -0800
    Re: Tetris rough draft (very rough) luserdroog <luser.droog@gmail.com> - 2019-11-22 21:47 -0800
      Re: Tetris rough draft (very rough) Julio Di Egidio <julio@diegidio.name> - 2019-11-23 05:47 -0800

csiph-web