Reactris Part VI: Rotating a piece

In the last post, I hooked up keyboard events to move around one of the game pieces. This time I’ll investigate how to make the piece rotate too.

Just like we used the SVG transform to scale and translate the pieces earlier, it can also be used for rotation.

Just to demonstrate this, I changed the code that formulates the transform to include a 5 degree rotation at the end:

    var transformString = "scale("+gridSize+" "+gridSize+") translate(" + this.props.x + " " + this.props.y + ") rotate(5)"

This results in something that looks like this:

Rotated five degrees.

Really what we want to do is accept a rotation angle as one of the props of the BlockShape component.

    var transformString = "scale("+gridSize+" "+gridSize+") translate(" + this.props.x + " " + this.props.y + ") rotate("+this.props.rotation+")"

unfortunately, if I run with this, all of the pieces are disappeared and I have a bunch of error messages saying that the transform attribute cannot be parsed. The issue is that now none of my Rectangle tags specify the rotation. And if you try to use a property that does not have a value specified for it, you get “undefined”. This brings up an important question that I have run into a couple times already but just worked around:

How do I specify a default value of a property in React.js?

This question is answered on this page http://facebook.github.io/react/docs/reusable-components.html

The answer is to implement the getDefaultProps function within the BlockShape component:

    getDefaultProps: function() {
    return {
      rotation: '0'
    };
    }

So now to add the rest of the plumbing so that I can control the rotation using the key event, I’m basically following the same steps that I did in the last tutorial:

Adding a new method to my ReactrisSVG component for rotating the current piece:

  rotatePiece: function( quarterTurns ){
      this.setState ({
          currentPieceRot:
              this.state.currentPieceRot+quarterTurns*90})
  }

Changing the ReactrisShape tag for the yellow piece to include the rotation:

  var currentPiece = <ReactrisShape ref="currentPiece" type="0" x={this.state.currentPiecePos[0]} y={this.state.currentPiecePos[1]} rotation={this.state.currentPieceRot} color="yellow"/>

Initializing the initial state of the currentPiecePos variable in the ReactrisSVG component:

  getInitialState: function()
  {
      return ({
          currentPiecePos: [1,1],
          currentPieceRot: 0
      });
  },

And changing the event handler to use the keys “1” and “2” to control rotation both clockwise and counterclockwise.

        charString = String.fromCharCode(e.keyCode)
    
        if (e.keyCode == '38') { context.movePiece(0,-1); }
        else if (e.keyCode == '40') { context.movePiece(0,1); }
        else if (e.keyCode == '37') { context.movePiece(-1,0); }
        else if (e.keyCode == '39') { context.movePiece(1,0); }
        else if (charString == '1') { context.rotatePiece(-1); }
        else if (charString == '2') { context.rotatePiece(1); }

Now this basically works (see http://jsfiddle.net/uglycoyote/z0aj3ysv/27/) but there are a couple things wrong with it:

Firstly, the piece is rotating around its corner, which causes it to swing up and out of view. Really we need to be rotating around a more central point. The trouble is when I wrote the arrays which define each of the game pieces, I used 0,0 as the upper-left corner of each piece. I’ll save this problem for later.

The more annoying problem at this point is that the key events are getting handled twice: once by the game, and then again by the browser. I noticed this a little bit with the arrow keys. They made the game piece move but also caused the browser to scroll around within the little tiny JSFiddle viewport that the game is in, which on my small laptop screen is not quite big enough to hold the entire SVG canvas. (if the monitor were bigger I might not have noticed this because the viewport wouldn’t scroll if the contents fit entirely inside).

When I started using the 1 and 2 keys, this was even more problematic. Currently i’m testing most of this under Firefox, and i have the “search when I start typing” setting turned on, which generally i find very useful, but in this case each time i press the 1 or 2 key it’s taking focus away from the game and acting as though I want to search for 1’s and 2’s in the page. However, I don’t have this problem under Chrome because Chrome does not have this feature (although I have used a plugin which implements this feature under Chrome on other machines)

Is there a way to have my event handler mark the key event as being handled so that the key event doesn’t get handled twice by two different systems?

It turns out that returning a value of false from the event handler cancels the event and prevents the browser from handling it:

        if (e.keyCode == '38') { context.movePiece(0,-1); return false; }
        else if (e.keyCode == '40') { context.movePiece(0,1); return false; }
        else if (e.keyCode == '37') { context.movePiece(-1,0); return false; }
        else if (e.keyCode == '39') { context.movePiece(1,0); return false; }
        else if (charString == '1') { context.rotatePiece(-1); return false; }
        else if (charString == '2') { context.rotatePiece(1); return false; }
       
           return true;

Now to tackle the pesky problem of the pivot point.

Actually, adding a couple more translations on to our SVG trasform solves this. This is where my games/graphics knowledge comes in handy. Rotation around a specific pivot point is equivalent to translating so that the pivot point becomes the new origin, rotating, and then translating again by the opposite of the pivot point offset.

For that yellow S-Shape, I want the pivot point to be at the centre of the second block from the left, so at 1.5, 0.5. Here’s my new transformString:

    var transformString = "scale("+gridSize+" "+gridSize+")   translate(" + this.props.x + " " + this.props.y + ") translate(1.5,0.5) rotate("+this.props.rotation+") translate(-1.5,-0.5)"

I may later want to have a different pivot point for each of the different shapes. But actually this 1.5, 0.5 looks like a decent choice of pivot point for most of the shapes.

Here’s the fiddle up to this point: http://jsfiddle.net/uglycoyote/z0aj3ysv/30/

That concludes this posting. In the next blog post I will need to start looking at some kind of a mechanism for shifting the controls to focus on different game pieces.

Reactris Part V: Moving a shape using the arrow keys

In the last posting, I succeeded in creating a generic block shape component that can represent and of the game pieces.

My next step is to start making this into a game by allowing the user to control the position of the pieces using the arrow keys.

Didn’t really know where to start, so I googled “javascript keyboard events” and found this useful Stack Overflow page: http://stackoverflow.com/questions/5597060/detecting-arrow-key-presses-in-javascript

I modified some code off one of the answers on that page so that each arrow key called into a movePiece function with different x,y values. For starters I just used an alert to make sure this was working, and it worked just fine.

document.onkeydown = checkKey;

function checkKey(e) {

    e = e || window.event;

    if (e.keyCode == '38') { movePiece(0,-1); }
    else if (e.keyCode == '40') { movePiece(0,1); }
    else if (e.keyCode == '37') { movePiece(-1,0); }
    else if (e.keyCode == '39') { movePiece(1,0); }
}

function movePiece( x, y )
{
    alert( "you want to move a piece by " + x + ", " + y );
}

Now how can we hook this in to our tetris game? The top level coponent (ReactrisSVG) will have to handle these key events and apply the movement to the ‘active’ game piece.

Figuring out how to actually hook this up to my React component took quite a bit of futzing around. My initial thought was to leave this movePiece function at the global scope and then have it call a method on my top level component.

So I added another movePiece function inside the dictionary that’s passed into AddClass (for the ReactrisSVG component), thinking I would just be able to call ReactrisSVG.movePiece. But this doesn’t work, because ReactrisSVG is a class and not an instance.

I did some googling around and ran in to this post which seemed like it was helpful:
http://stackoverflow.com/questions/24841855/react-js-access-to-component-methods

where the question-asker says “Why I can’t access the component methods from “outside” in React.js? Why it’s not possible and is there any way to solve it?”

the top rated answer suggested using “refs”: http://facebook.github.io/react/docs/more-about-refs.html

basically the idea with refs is that inside your render() function when you create subcomponents with a jsx tag, you can give them a refs=”instanceName” attribute, and then the parent component can later access that specific instance of the subcomponent as this.refs.instanceName.

So I attempted to give my ReactrisSVG element a name ‘theReactrisSVG’, but I ran into an error saying that I could not use refs with a top-level component. Then I went down the rabbit hole of trying to create an even higher-level component to put my ReactrisSVG inside, so that i could give it a name. But it was a chicken and egg problem, I still had no way to call a component method on the new top-level component.

So I eventually decided that I was thinking about it all wrong, rather than adding the document.onkeydown handler in the global scope, I should register this event handler within the ReactrisSVG component.

It’s not completely clear to me what the appropriate place to do that is because the component did not really have any initialization function. I ended up adding a new componentDidMount method, which is automatically called after your component has been created and added to the DOM.

The new ReactrisSVG component with key handling then looked like this:

var ReactrisSVG = React.createClass({
  getInitialState: function()
  {
      return ({
          currentPiecePos: [1,1]
      });
  },
  componentDidMount: function()
  {
      context = this;
      document.onkeydown = function(e)
      {
        e = e || window.event;
    
        if (e.keyCode == '38') { context.movePiece(0,-1); }
        else if (e.keyCode == '40') { context.movePiece(0,1); }
        else if (e.keyCode == '37') { context.movePiece(-1,0); }
        else if (e.keyCode == '39') { context.movePiece(1,0); }
      }
  },
      
  render: function() {

  var svgWidth = 300
  var svgHeight = 300

  var currentPiece = <ReactrisShape ref="currentPiece" type="0" x={this.state.currentPiecePos[0]} y={this.state.currentPiecePos[1]} color="yellow"/>

  return <svg width={svgWidth} height={svgHeight}
       xmlns="http://www.w3.org/2000/svg">
        {currentPiece}
        <ReactrisShape type="1" x="1" y="4" color="orange"/>
        <ReactrisShape type="2" x="5" y="1" color="red"/>
        <ReactrisShape type="3" x="5" y="4" color="violet"/>
        <ReactrisShape type="4" x="1" y="7" color="cyan"/>
        <ReactrisShape type="5" x="6" y="7" color="green"/>
        <ReactrisShape type="6" x="1" y="9" color="lightgreen"/>
  </svg>
  },
  
  movePiece: function(x,y){
  
      this.setState ({
          currentPiecePos:            
              [this.state.currentPiecePos[0]+x,
              this.state.currentPiecePos[1]+y]
      });

  }
});

In this updated version of the jsfiddle, you can now use the arrow keys to move around the yellow piece, which is the one which is hooked up to the currentPiecePos state variable.

http://jsfiddle.net/uglycoyote/z0aj3ysv/26/

Another subtle trick in the code above which took me a while to figure out, but what might be obvious to someone who’s been doing javascript for a long time, is that I could not call “this.movePiece” inside of my event handler, because “this” no longer referred to my ReactrisSVG component. I’m not quite sure what “this” refers to inside the event handler, but I think I have heard that it refers to the DOM element that sent the event. So, the fix for this is to stow away the reference to the ReactrisSVG component into a variable called “context” which is then available inside the handler.

In the next post I’ll look in to how I extend this to allow rotation of the game piece.

Reactris Part IV: Data-driven shapes

In the last blog entry, I was defining the S-Shaped tetris piece like this:

return <g transform={transformString}>
<Rectangle x="0" y="0" width="1" height="1"/>
    <Rectangle x="1" y="0" width="1" height="1"/>
    <Rectangle x="1" y="1" width="1" height="1"/>
    <Rectangle x="2" y="1" width="1" height="1"/>
</g>

But before creating a whole bunch of other pieces in this format, I wanted to try to make a more compact specification of the shape, like this:

blocks = [[0,0],[1,0],[1,1],[2,1]]

My first thought was to extract out the rectangles into a separate variable, like this:

    rectangles =     <Rectangle x="0" y="0" width="1" height="1"/>
        <Rectangle x="1" y="0" width="1" height="1"/>
        <Rectangle x="1" y="1" width="1" height="1"/>
        <Rectangle x="2" y="1" width="1" height="1"/>


    return <g transform={transformString} fill={this.props.color}>
    {rectangles}
    </g>

However, then you just get the complaint “Adjacent XJS elements must be wrapped in an enclosing tag” which I encountered also in the last post. That was my reason for adding the grouping element around the rectangles to begin with.

It turns out that we can get around this by appending all of the rectangle JSX elements into a list like so:

    rectangles = [<Rectangle x="0" y="0" width="1" height="1"/>,
        <Rectangle x="1" y="0" width="1" height="1"/>,
        <Rectangle x="1" y="1" width="1" height="1"/>,
        <Rectangle x="2" y="1" width="1" height="1"/>]

    return <g transform={transformString} fill={this.props.color}>
    {rectangles}
    </g>

My next thought, coming from working in a languages like c++ was to write a ‘for’ loop to construct this list of rectangles from the blocks array. But javascript has the much-nicer functional-programming style ‘map’ operation, allowing me to construct the rectangles by writing a function that converts [x,y] coordinates into Rectangle elements, and then mapping my function to each element of the array to create the new list of Rectangles:

var ShapeS = React.createClass({
    blocks:[[0,0],[1,0],[1,1],[2,1]],
    render:function(){
    
    var transformString = "scale("+gridSize+" "+gridSize+") translate(" + this.props.x + " " + this.props.y + ")"

    rectangles = this.blocks.map(function(xy,i){return <Rectangle x={xy[0]} y={xy[1]} width="1" height="1"/>})

    return <g transform={transformString} fill={this.props.color}>
    {rectangles}
    </g>
        ;
    }
})

(http://jsfiddle.net/uglycoyote/z0aj3ysv/20/)

My next goal is to break the definition of the blocks out of this class, so that I can have a more generic shape class:

var ShapeS = React.createClass({
    blocks:[[0,0],[1,0],[1,1],[2,1]],
    render:function(){
        return <BlockShape blocks={this.blocks}/>
    }
})

var BlockShape = React.createClass({
    render:function(){
    
    var transformString = "scale("+gridSize+" "+gridSize+") translate(" + this.props.x + " " + this.props.y + ")"

    rectangles = this.props.blocks.map(function(xy,i){return <Rectangle x={xy[0]} y={xy[1]} width="1" height="1"/>})

    return <g transform={transformString} fill={this.props.color}>
    {rectangles}
    </g>
        ;
    }
})

Unfortunately, this code has an error: the props.x and props.y specified on the ShapeS tag no longer make it down into the transformString.

Fortunately, I recalled seeing a ‘transferPropsTo’ function in some of the React demos, and didn’t quite understand what it was all about when I saw it, but now this sounds like exactly what I need. But after doing some further reading, it appears that the ‘transferPropsTo’ function is deprecated and there’s a new way of doing it, described in this section of the React docs:

http://facebook.github.io/react/docs/transferring-props.html

Long story short, the fix for this is just to add {…this.props} inside the tag and all of the properties of the ShapeS component are passed down in to the BlockShape component.

        return <BlockShape {...this.props} blocks={this.blocks}/>

(http://jsfiddle.net/z0aj3ysv/21/)

But rather than creating a separate class for each of the different tetris shapes I thought it would be better to just have an array of the different shape descriptions and be able to choose the shape using an index. This way later on when I need to choose a shape at random, I can select my shape easily using a random number and not need to create some kind of lookup table with the different shape classes.

In the code below, I make an array containing the the descriptions of each of the pieces, and make a generic ReactrisShape component that is parameterized by the shape type:

reactrisShapeDescriptions = [
    // S-Shape
    [[0,0],[1,0],[1,1],[2,1]],
    // Mirrored S-Shape
    [[0,1],[1,1],[1,0],[2,0]],
    // L-Shape
    [[0,0],[1,0],[2,0],[2,1]],
    // Mirrored L-Shape
    [[0,1],[1,1],[2,1],[2,0]],
    // Long Stick
    [[0,0],[1,0],[2,0],[3,0]],
    // Square
    [[0,0],[1,0],[0,1],[1,1]],
    // T-Shape
    [[0,0],[1,0],[1,1],[2,0]],
    
]

var ReactrisShape = React.createClass({
    
    render:function(){
        return <BlockShape {...this.props} blocks={reactrisShapeDescriptions[this.props.type]}/>
    }
})

To display all of the shapes, I then changed my top level component to contain one of each of the types and gave them all different xy coordinates and colors.

        <ReactrisShape type="0" x="1" y="1" color="yellow"/>
        <ReactrisShape type="1" x="1" y="4" color="orange"/>
        <ReactrisShape type="2" x="5" y="1" color="red"/>
        <ReactrisShape type="3" x="5" y="4" color="violet"/>
        <ReactrisShape type="4" x="1" y="7" color="cyan"/>
        <ReactrisShape type="5" x="6" y="7" color="green"/>
        <ReactrisShape type="6" x="1" y="9" color="lightgreen"/>

(http://jsfiddle.net/z0aj3ysv/24/)

Now we have something that looks like this:

All the different Reactris shapes

In the next blog post, I’ll start looking in to how to move the game pieces around in response to arrow key events.

Follow this link to Part V of this blog.

Reactris Part III: Shape Components

In the last post, I created a SVG Rectangle component which was parameterized by x,y, width, and height, and I concluded the post by drawing four rectangles to make a tetris “S” shape piece. (it takes some imagination to see it as the letter “S”, but you know the one i mean.)

Next I’ll try to create a single component that represents this shape.

here’s my first attempt at doing this:

var ShapeS = React.createClass({
    render:function(){
    return 
    
    <Rectangle x="10" y="10" width="20" height="20"/>
        <Rectangle x="30" y="10" width="20" height="20"/>
        <Rectangle x="30" y="30" width="20" height="20"/>
        <Rectangle x="50" y="30" width="20" height="20"/>;
    }
})

but this doesn’t work, in my developer tools window, I see the message: “Adjacent XJS elements must be wrapped in an enclosing tag”. What this is trying to tell me is that I cannot return four sibling Rectangle elements, I need to wrap them all in some higher level tag. If I was doing regular old HTML here I would wrap them in a Div, but I’m not sure if it make sense to have a Div inside of an SVG element.

A bunch of googling around for terms like “div inside svg”, “svg dummy parent”, etc eventually led to this page, which was interesting but didn’t answer my question:

http://biesnecker.com/2014/10/22/using-reactjs-to-draw-dynamic-svgs/

(but has a few neat little ReactJS SVG demos)

and then finally I came to understand that SVG has a tag called simply “g”:

The g element is a container used to group objects. Transformations applied to the g element are performed on all of its child elements. Attributes applied are inherited by child elements. In addition, it can be used to define complex objects that can later be referenced with the element.

(https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g)

So, if I change the code above to include the ‘g’ tag it is able to work again:

var ShapeS = React.createClass({
    render:function(){
    return <g>
    <Rectangle x="10" y="10" width="20" height="20"/>
        <Rectangle x="30" y="10" width="20" height="20"/>
        <Rectangle x="30" y="30" width="20" height="20"/>
        <Rectangle x="50" y="30" width="20" height="20"/>
    </g>
        ;
    }
})

http://jsfiddle.net/uglycoyote/z0aj3ysv/8/

The blockquote above from the Mozilla documentation about the ‘g’ tag also hints at how we can now move around this shape as a whole. Initially I had been planning to parameterize the ShapeS component with an x and y and then calculating each rectangle’s x and y something like this:

    <Rectangle x="{10+this.props.x}" y="{10+this.props.y}" width="20" height="20"/>

But it would less verbose to simply leave the absolute coordinates in the rectangles the way they are and then to apply a translation to the entire ‘g’ element.

The Mozilla page for ‘g’ contains a list of the attributes that are allowable on the ‘g’ tag, one of which is the ‘transform’ attribute, which is linked to this page:

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform

So I can do something like this:

var ShapeS = React.createClass({
    render:function(){
    return <g transform="translate(60 60)">
    <Rectangle x="0" y="0" width="20" height="20"/>
        <Rectangle x="20" y="0" width="20" height="20"/>
        <Rectangle x="20" y="20" width="20" height="20"/>
        <Rectangle x="40" y="20" width="20" height="20"/>
    </g>
        ;
    }
})

which draws the S-Shape at coordinates 60,60. The next step is to change the hard-coded 60,60 to use some x and y properties passed in from above. This seems like it should be trivial, the same kind of thing that we already did with the Rectangle component.

So I try changing the ‘g’ tag to look like this:

<g transform="translate({this.props.x} {this.props.y})">

But that does not work, I get an error saying:

Unexpected value translate({this.props.x} {this.props.y}) parsing transform attribute

doing a quick google search of that error message, I run across a Stack Overflow post where someone got an error with the same wording, but he’s using D3 and SVG, and not ReactJS. So this is something to do with an unexpected attribute value while parsing the SVG, it’s as if React is not substituting the curly braces with the property values before the attribute is being evaluated as SVG.

To work around this, it seems to help if I just formulate the attribute value as a string beforehand rather than embedding all of this in the JSX. This code works much better:

 
    var transformString = "translate(" + this.props.x + " " + this.props.y + ")"    
    return <g transform={transformString}>

(http://jsfiddle.net/uglycoyote/z0aj3ysv/9/)

Units Cleanup

Now, I have rather arbitrarily decided up to this point that the size of all of my rectangles in the S-Shape should be 20 units. But what if someone came along and told me they wanted the tetris shapes to appear slightly bigger or smaller? I’ve got so many hard-coded multiples of 20 in the code that it would be kind of hard to change that after the fact. But, hey wait, what did that first “S” in “SVG” stand for?? Oh yeah it’s “Scalable”. So I can apply a scaling to my coordinate system to make the blocks whatever size I want.

From that perspective, since the entire tetris game is laid out on a square grid, it seems like it would be nice to specify all of the shape coordinates in multiples of 1, and then just using scaling afterwards to make the block appear whatever size i want.

Here I go with that:

    var transformString = "translate(" + this.props.x + " " + this.props.y + ") scale(20 20)"
    
    return <g transform={transformString}>
    <Rectangle x="0" y="0" width="1" height="1"/>
        <Rectangle x="1" y="0" width="1" height="1"/>
        <Rectangle x="1" y="1" width="1" height="1"/>
        <Rectangle x="2" y="1" width="1" height="1"/>
    </g>

(http://jsfiddle.net/uglycoyote/z0aj3ysv/11/)

Now that kind of worked, but hey what happened to my nice grey blocks and why did the shape change slightly?

Funny Block Shape

What’s going on here is that I’m using both ‘stroke’ and ‘fill’ on my shapes. They have a black outline which happens to be of width 1 by default. When all of my shapes were of size 20, the width 1 outline was a nice thin line border, but now the outline of size 1 actually obscures the entire box!

The answer here is the css stroke-width property. Lets dial that down to what it was before — 1/20th the size of the box, which would be 0.05.

rect
 {
     fill : slategray;
     stroke: black;
     stroke-width: 0.05;
 }

Now we have this:

Two S-Shape pieces

at this point (http://jsfiddle.net/uglycoyote/z0aj3ysv/12/) I am still specifying the positions of the pieces in multiples of 20, as seen here

        <ShapeS x="0" y="0"/>
        <ShapeS x="80" y="80"/>

That’s because of the order of my translation versus scaling, which is important. Since the translation happens first, it’s happening in the coordinate space where one unit is one pixel. If I reverse the order like this:

    var transformString = "scale(20 20) translate(" + this.props.x + " " + this.props.y + ")"

Then what used to be 80,80 becomes 4,4 and specifying the shape coordinates like this:

        <ShapeS x="0" y="0"/>
        <ShapeS x="4" y="4"/>

puts them in the same position as before.

Another nice thing about the SVG ‘g’ element that I realized when looking at the documentation is that attributes like color trickle down to group members. So I can change my ‘g’ to have an orange fill color:

<g transform={transformString} fill="orange">

which didn’t immediately work, because I had already specified fill:slategray in the css of the Rectangle element, and since that’s more specific than the ‘g’ element, the slategray takes precedence. But if I remove the fill color from the rectangle css, then my orange color falls through to all of the rectangles in the shape.

But of course, this should be a property again…

<g transform={transformString} fill={this.props.color}>

and then I can pass the color through as an attribute of the SShape tag:

        <ShapeS x="0" y="0" color="orange"/>
        <ShapeS x="4" y="4" color="violet"/>

orange and violet pieces

it’s almost time to create the other tetris shapes, but I realized that I still had a hard-coded grid size of 20 within the code that builds the ‘transform’ string, and I didn’t really want to copy-paste code with a magic number like this. So I parameterized this as a variable:

    var transformString = "scale("+gridSize+" "+gridSize+") translate(" + this.props.x + " " + this.props.y + ")"

I debated about whether to make this another property, but it seemed like it would be awkward to have to specify this gridsize as an attribute of every shape I create. In Tetris, this is really a global, a number I only want to specify once. So in this case I just put this ‘var gridSize’ at the top of the file. React purists might frown on this, because from what I have read about React components, the idea is that the output of the component should only depend on the properties and state of the component, otherwise your component is not “deterministic”. This is good advice, you definitely don’t want to have your component’s output depending on some outside variable that is going to change. However, it seems appropriate or at least less evil to depend on a global which is truly constant.

The way I have it set up is nice, I can go and change the gridsize in one place and make the shapes bigger:

Bigger shapes

…or smaller…

Smaller Shapes

Now, I’ve gotten rid of the magic numbers in the SShape class, but it’s still a bit verbose to go copying this code and making all kinds of different versions of it. It seems like there should be a simpler way to describe a tetris shape. The S-Shape could really just be described as a list of square x,y coordinates like this:

[[0,0],[1,0],[1,1],[2,1]]

In my next post I’ll look at how to generate Rectangle tags from this simpler description of the shape, which will make it easy to have a really compact specification of the different types of tetris pieces.

Follow this link to Part IV of this blog.

Reactris Part II: More Squares!

In my last post I started learning React.js down the road to creating a simple SVG tetris game.

I googled “Reactris” to see if my blog had been indexed by google yet, and hilariously enough I found someone else who had also made a tetris clone in React called Reactris (https://github.com/jmorrell/reactris).  How unoriginal am I?

Well if unoriginality deterred me, I suppose I would not be making a tetris clone.   The point here is not to create a novel game but to explore React.   At least jmorrell doesn’t have an identical blog post (that I could find).  He took a stlightly different path, using HTML Canvas rather than SVG.   I was surprised to see how many files he broke everything up into!

Anyhow, carrying on with where I was…

This time I thought I would try mucking around with these ideas in an online code editor.  I looked at CodePen first, but it was not obvious if they supported external frameworks like React.  JsFiddle has all kinds of different framework options readily apparent in the left pane, so I started there.

If you google for jsfiddle react jsx template, you find a few different starting points.  I chose this one:

http://jsfiddle.net/vjeux/kb3gN/

which simply pulls in some external “react-js-fiddle-integration” script and gives you a “hello world” component to start out with.  From there it was pretty simple to cut and paste the HTML, CSS, and Javascript from the last blog post and get something started:  http://jsfiddle.net/uglycoyote/z0aj3ysv/3/

So in the current incarnation I have just a single React component which emits the HTML for an SVG element with a single rectangle.  Obviously I want to have multiple rectangles so the next step is to make the rectangle into its own component.

That looks something like this:

var Rectangle = React.createClass({
    render:function(){
        
       var x=10
       var y=10
       var width=100
       var height=50
       
       return <rect x={x} y={y} width={width} height={height}/>

    }
}
)

and then I can replace the HTML (or JSX) emitted by the main component (which I have now renamed to ReactrisSVG) with:

  return <svg width={svgWidth} height={svgHeight}
       viewBox="0 0 {svgWidth} {svgHeight}"
       xmlns="http://www.w3.org/2000/svg">

        <Rectangle/>
  </svg>

(http://jsfiddle.net/uglycoyote/z0aj3ysv/4/)

So far I haven’t made any effort to parameterize the rectangle. I could put 1000 Rectangle tags into my SVG component and they would all be the same size and at the same spot.

So the logical next step is to add some parameters to the Rectangle tag. React calls these properties or just ‘props’. As soon as you add some attributes to your HTML tag like this:

        <Rectangle x="10" y="10" width="20" height="20"/>

You can access them from your component as members of this.props:

var Rectangle = React.createClass({
    render:function(){
               
       return <rect x={this.props.x} y={this.props.y} width={this.props.width} height={this.props.height}/>

    }
}
)

http://jsfiddle.net/uglycoyote/z0aj3ysv/5/

This seems, at the same time, both simple and elegant and also scary and brittle. It’s really nice that you can pipe data from your HTML tags through so easily, but on the other hand it seems like there’s no place in the component where there’s a clear declaration of what attributes/properties are accepted. I could imagine if someone writes a larger component, there could be enough code that it could be confusing or intimidating to try to figure out which props are accepted. I could also imagine the pain involved in trying to rename props after they are being used in HTML in a lot of other places. I guess this is the nature of the Web and dynamic languages, but it seems like it would be fraught with peril in a larger production environment.

Anyhow, with just a few of these parameterized rectangle tags we can now display our first tetris piece:

        <Rectangle x="10" y="10" width="20" height="20"/>
        <Rectangle x="30" y="10" width="20" height="20"/>
        <Rectangle x="30" y="30" width="20" height="20"/>
        <Rectangle x="50" y="30" width="20" height="20"/>

http://jsfiddle.net/uglycoyote/z0aj3ysv/6/

Tetris block screen shot

And that’s a wrap for this post.

In the next post(s) I will explore creating a component to represent a tetris piece, animating the pieces, and the different between React “props” vs “state”

Follow this link to Part III of this blog.

Reactris, part I : Getting Started

I’m trying to learn how React.js works.  I have a website project that I want to apply it to, but that’s already wrapped up with too many other different technologies and I want to understand how React works better before trying to fit it in to a larger project.

So I thought I would tackle something simpler with React, but something that’s a little outside of the box, something that would hopefully be interesting and require some thought rather than just verbatim copying of existing samples.

I thought I would try to make a Tetris clone using React.

Getting the samples set up

First things first, I needed to be able to run the react.js samples.

I went to their getting started page (http://facebook.github.io/react/docs/getting-started.html) and downloaded the starter package (Version 0.12.1 is what is up on their site at the time of this writing)

I found that the simpler of these samples worked by browsing directly to the file, but the ones which have a separate .js and .html file do not work.  You’ll see something like this in the chrome dev tools console:

XMLHttpRequest cannot load file:///Users/mike/Downloads/react-0.12.1%202/examples/basic-jsx-external/example.js. Cross origin requests are only supported for protocol schemes: http, data, chrome-extension, https, chrome-extension-resource. VM166 JSXTransformer.js:219load

Fortunately, the React developers added a helpful message to the page:

If you can see this, React is not working right. This is probably because you’re viewing this on your file system instead of a web server. Try running

python -m SimpleHTTPServer

It’s worth noting that you should do this inside the ‘examples’ directory of their samples package (as opposed to running it inside a subdirectory for  a specific sample).   The samples reference a ‘shared’ folder which contains css and other resources which are shared between different samples.

I also found, somewhat annoyingly, that most of the samples get error 404’s when they request some .map files like es5-shim.map, which it is looking for under the shared/thirdparty directory but is not present.  Failure to find these doesn’t prevent the samples from working though.

 Choosing a sample to extend

For the purpose of this example, I thought it would be cleanest to use JSX and use the ‘external’ sample (with the .js in a separate file rather than embedded in the HTML).

In case you haven’t read up on JSX yet, the basic idea is that it’s an HTML-like syntax that’s embedded in the javascript code in lieu of using either (A) An HTML templating engine or (B) a more javascripty API for manipulating the DOM.

To that end, I made a copy of the ‘basic-jsx-external’ sample directory and started to modify the javascript in the copied directory.

Setting up an SVG Canvas inside of the React sample

I wanted to use SVG as my rendering technology for displaying my tetris game.  I haven’t seen an React sample code using SVG but since SVG is just another HTML-like syntax, and part of the DOM, I saw no reason why this should not work.

I’m not an expert on SVG either, so Baby steps… first thing is how do we draw a rectangle.  Here are the docs for the ‘rect’ SVG element from Mozilla:

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect

inside of there I found this nice little snippet

<?xml version="1.0"?>
<svg width="120" height="120"
     viewBox="0 0 120 120"
     xmlns="http://www.w3.org/2000/svg">

  <rect x="10" y="10" width="100" height="100"/>
</svg>

Fortunately this translates over into JSX without any trouble, so I simply modified the return value of the ExampleApplication from the basic-jsx-external sample:

var ExampleApplication = React.createClass({
  render: function() {

  return <svg width="120" height="120"
       viewBox="0 0 120 120"
       xmlns="http://www.w3.org/2000/svg">

    <rect x="10" y="10" width="100" height="100"/>
  </svg>
  }
});

and there we have it, our sample now has on SVG canvas with a rectangle on it.

Screen Shot 2014-12-10 at 12.46.19 AM
Data driven Rectangle

so far this is not very interesting, I’ve just gotten React to spit out some static HTML.

Lets take the next step and put the svg canvas dimensions and the rectangle dimensions into local variables, so that the HTML is data driven



var ExampleApplication = React.createClass({
  render: function() {

  var svgWidth = 300
  var svgHeight = 300

  var x=10
  var y=10
  var width=100
  var height=50

  return <svg width={svgWidth} height={svgHeight}
       viewBox="0 0 {svgWidth} {svgHeight}"
       xmlns="http://www.w3.org/2000/svg">

    <rect x={x} y={y} width={width} height={height}/>
  </svg>
  }
});

 

While I was at it, I shuffled around the HTML a bit from the sample, got rid of some of the extra stuff in there and added some styles for the SVG and Rect elements to make them stand out a bit more from the page:


  <style>

    svg
    {
        background-color: #EEEEEE;
    }

    rect
    {
        fill : gray;
        border: 1px;
        stroke: black;
    }

  </style>

Here’s what it looks like after that:

Screen Shot 2014-12-10 at 1.01.49 AM

hey, it’s starting to look like something. Time to take a rest.

In the next posting, I’ll start hooking this in to React in a more interesting way. It seems to be the ethos of React to break everything up into separate components with their own createClass and render functions, so my plan next time is to make the rectangle a component, so that it’s easy to instantiate and control a bunch of individual rectangles.

Follow this link to the Part II of this blog.