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.model.queue.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" {{#player.hasQueuedRequests}}disabled="disabled"{{/player.hasQueuedRequests}}>Replay!</button>
<span>{{#player.hasQueuedRequests}}Saving!{{/player.hasQueuedRequests}}</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.element.html(can.view('avatar', {
player : this.player,
isMoving : this.isMoving
}));
// 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', min(this.player.attr('position.top') - 5, 0));
} else if(direction...