JSFiddle - React, Tailwind, and code Playground

by dmihaelkonjevic

HTML

<script src="http://canjs.us/release/latest/can.jquery.js"></script>
<script src="http://canjs.us/release/latest/can.fixture.js"></script>
<script src="http://canjs.us/release/latest/can.view.mustache.js"></script>
<script src="http://canjs.us/release/latest/can.observe.backup.js"></script>
<script src="http://canjs.us/release/latest/can.object.js"></script>
<strong>Move around with the arrow keys, and click replay after you're done.</strong>
<div class="rpg"></div>

<script type="text/mustache" id="avatar">
  <div class="map">
      <div class="character {{#isMoving}}moving{{/isMoving}} {{ player.position.direction }}" style="left: {{ player.position.left }}px; top: {{ player.position.top}}px"></div>
    <div class="fire-pit"></div> 
  </div>
  <button class="replay" {{#isSaving}}disabled="disabled"{{/isSaving}}>Replay!</button>
  <span>{{#isSaving}}Saving!{{/isSaving}}</span>
</script>

CSS

body {
        font-family: Arial, sans-serif;
      }
      .character {
        width: 24px;
        height: 32px;
        position: absolute;
        z-index: 1000;
        /* created with http://charas-project.net/charas2/index.php */
        background-image: url('http://s21.postimage.org/byyd7owj7/static.gif');
      }
      .fire-pit {
        width: 24px;
        height: 24px;
        background: url('http://s21.postimage.org/krfbvdho3/fire.gif');
        position: absolute;
        top: 100px;
        left: 80px;
      }
      .up {
        background-position: 0 0;
      }
      .down {
        background-position: 0 -64px;
      }
      .right {
        background-position: 0 -32px;
      }
      .left {
        background-position: 0 -96px;
      }
      .moving {
        background-image: url('http://s21.postimage.org/b85n1wu5v/animated.gif');
      }
      .map {
        width: 300px;
        height: 300px;
        position: relative;
        margin: 10px 0;
        /* Texture from http://zooboingreview.blogspot.com/2009/11/seamless-texture-more-nice-grass.html */
        background-image: url('http://s21.postimage.org/fxvkqil6f/363_tile_Grass.jpg');
      }

JavaScript

$(document).ready(function(){

/* SERVER EMULATION */

	var getRandomInt = function(min, max) {
		return Math.floor(Math.random() * (max - min + 1)) + min;
	}

	var positions = [];

	can.fixture('POST /players', function(req){
		var attrs = req.data || {};
		positions.push(attrs.position); // Save current position
		attrs.id  = 1;
		return attrs;
	})

	can.fixture('PUT /players/{id}', function(req, respondWith){
		var attrs    = req.data || {},
				position = attrs.position;

		if(position.top > 80 && position.top < 100 && position.left > 60 && position.left < 100){ // you stepped on the fire, you die
			respondWith(406);
		} else {
				positions.push(attrs.position);  // save current position
				setTimeout(function(){
					respondWith(attrs);
				}, getRandomInt(10, 50)) // change delay to simulate slow and spotty connection
		}
	})

	can.fixture('GET /game', function(req){
		return positions;
	})

	var directions = {
		37 : 'LEFT',
		38 : 'UP',
		39 : 'RIGHT',
		40 : 'DOWN'
	},
	max = function(val, max){
		return val > max ? max : val;
	},
	min = function(val, min){
		return val < min ? min : val;
	};

	var Player = can.Model({
		create : "POST /players",
		update : "PUT /players/{id}"
	}, {});

	var Replay = can.Model({
		findAll : "GET /game"
	}, {})


	var RPG = can.Control({
		init : function(){
			this.player = new Player({
				position: {
					top  : 0,
					left : 0,
					direction: "down"
				}
			});
			this.isMoving = can.compute(false); 
			this.isSaving = can.compute(false);
			this.element.html(can.view('avatar', {
					player : this.player,
					isMoving : this.isMoving,
					isSaving : this.isSaving
			}));
			
			// save starting position
			this.savePosition();
		},
		move : function(direction){
			var position, direction;
			if(direction){
				this.isMoving(true);
				this.player.attr('position.direction', direction.toLowerCase());
				// move the avatar in the right direction
				if(direction === 'UP'){
					this.player.attr('position.top',...