Skip to content

Commit

Permalink
Fixed phantom bomb drop
Browse files Browse the repository at this point in the history
  • Loading branch information
MrJaba committed Jun 5, 2010
1 parent 6d213e9 commit 2af9bb8
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 44 deletions.
63 changes: 23 additions & 40 deletions controllers/game_controller.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,103 +4,86 @@ class GameController < Cramp::Controller::Websocket
periodic_timer :cleanup, :every => 1 periodic_timer :cleanup, :every => 1
on_data :receive_message on_data :receive_message
class << self class << self
attr_accessor :player_states
attr_accessor :games
attr_accessor :bomb_positions
attr_accessor :connection_to_games attr_accessor :connection_to_games
end end
TIMEOUT = 20
@games = []
@connection_to_games = {} @connection_to_games = {}
@player_states = {}
@bomb_positions = {}


def receive_message(data) def receive_message(data)
message = JSON.parse(data) message = JSON.parse(data)
type = message['type'] type = message['type']
uuid = message['uuid'] uuid = message['uuid']
update_last_message_time(uuid) if Game.player_in_game?(uuid) || type == "register"
self.send("receive_#{type}", message, uuid) update_last_message_time(uuid)
self.send("receive_#{type}", message, uuid)
end
end end


def push_states def push_states
data = {:type => 'update_positions', :positions => game_states}.to_json data = {:type => 'update_positions', :positions => game_states_for_connection}.to_json
render data render data
end end


def push_bombs def push_bombs
data = {:type => 'update_bombs', :positions => GameController.bomb_positions}.to_json data = {:type => 'update_bombs', :positions => Game.bomb_positions}.to_json
render data render data
end end


private private


def receive_register(message, null_uuid=nil) def receive_register(message, null_uuid=nil)
player_uuid = UUID.new.generate player_uuid = UUID.new.generate
game = find_or_create_game game = Game.find_or_create_game
GameController.connection_to_games[self.object_id] = game GameController.connection_to_games[self.object_id] = game
player = game.create_player(player_uuid) player = game.create_player(player_uuid)
GameController.player_states[player_uuid] = player Game.player_states[player_uuid] = player
render ({:type => 'register', :uuid => player_uuid, :colour => player.colour}).to_json render ({:type => 'register', :uuid => player_uuid, :colour => player.colour}).to_json
end end


def receive_player_move(message, uuid) def receive_player_move(message, uuid)
if( uuid && GameController.player_states[uuid] ) if( uuid && Game.player_states[uuid] )
GameController.player_states[uuid].update({:x => message['data']['x'], :y => message['data']['y']}) Game.player_states[uuid].update({:x => message['data']['x'], :y => message['data']['y']})
end end
end end


def receive_send_bomb_drop(message, uuid) def receive_send_bomb_drop(message, uuid)
position = {:x => message['data']['x'], :y => message['data']['y']} position = {:x => message['data']['x'], :y => message['data']['y']}
GameController.bomb_positions[uuid] = position unless uuid.nil? Game.bomb_positions[uuid] = position if !uuid.nil?
end end


def receive_send_bomb_detonate(message, uuid) def receive_send_bomb_detonate(message, uuid)
bomb_id = message['data'] bomb_id = message['data']
GameController.bomb_positions.delete(bomb_id) unless bomb_id.nil? Game.bomb_positions.delete(bomb_id) if !bomb_id.nil?
end end


def receive_send_kill_player(message, uuid) def receive_send_kill_player(message, uuid)
GameController.player_states[uuid].score += 1 if GameController.player_states[uuid] Game.player_states[uuid].score += 1 if Game.player_states[uuid]
player_killed = message['data']['killed'] player_killed = message['data']['killed']
GameController.player_states[player_killed].respawn(:death) if GameController.player_states[player_killed] Game.player_states[player_killed].respawn if Game.player_states[player_killed]
end end


def receive_send_reset_state(message, uuid) def receive_send_reset_state(message, uuid)
GameController.player_states[uuid].clearState Game.player_states[uuid].clearState
end end


def cleanup def cleanup
states = GameController.player_states.dup states = Game.player_states.dup
states.each_pair do |uuid, state| states.each_pair do |uuid, state|
if timed_out?(state) if Game.timed_out?(state)
GameController.player_states[uuid].game.delete_player(uuid) Game.player_states[uuid].game.delete_player(uuid)
GameController.player_states.delete(uuid) Game.player_states.delete(uuid)
end end
end end
end end


def timed_out?(player_state)
(Time.now - player_state.last_message_time) > TIMEOUT
end

def update_last_message_time(uuid) def update_last_message_time(uuid)
if( uuid && GameController.player_states[uuid] ) if( uuid && Game.player_states[uuid] )
GameController.player_states[uuid].last_message_time = Time.now Game.player_states[uuid].last_message_time = Time.now
end end
end end


def game_states #Only push the game that this connection(client) is playing in
def game_states_for_connection
GameController.connection_to_games[self.object_id].player_states rescue {} GameController.connection_to_games[self.object_id].player_states rescue {}
end end


def find_or_create_game
game = GameController.games.select{|game| !game.full? }.first
if game.nil?
game = Game.new
GameController.games << game
end
game
end

end end
27 changes: 27 additions & 0 deletions models/game.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,17 @@
class Game class Game
COLOURS = %w{ blue brown red yellow } COLOURS = %w{ blue brown red yellow }
TIMEOUT = 20
attr_accessor :players attr_accessor :players


class << self
attr_accessor :player_states
attr_accessor :games
attr_accessor :bomb_positions
end
@games = []
@player_states = {}
@bomb_positions = {}

def initialize def initialize
self.players = [] self.players = []
end end
Expand Down Expand Up @@ -36,5 +46,22 @@ def player_states
def full? def full?
players.size == 4 players.size == 4
end end

def self.find_or_create_game
game = Game.games.select{|game| !game.full? }.first
if game.nil?
game = Game.new
Game.games << game
end
game
end

def self.timed_out?(player_state)
(Time.now - player_state.last_message_time) > TIMEOUT
end

def self.player_in_game?(uuid)
Game.player_states.include?(uuid)
end


end end
2 changes: 1 addition & 1 deletion models/player.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def update(attributes)
self.y = attributes[:y] self.y = attributes[:y]
end end


def respawn(cause=:start) def respawn
self.x = self.spawn.first self.x = self.spawn.first
self.y = self.spawn.last self.y = self.spawn.last
self.state = 'restart' self.state = 'restart'
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="javascripts/bomb.js" type="text/javascript"></script> <script src="javascripts/bomb.js" type="text/javascript"></script>
<script src="javascripts/sprite.js" type="text/javascript"></script> <script src="javascripts/sprite.js" type="text/javascript"></script>
<script src="javascripts/movement.js" type="text/javascript"></script> <script src="javascripts/movement.js" type="text/javascript"></script>
<script src="javascripts/jquery.dump.js" type="text/javascript"></script>
<link rel="Stylesheet" href="/css/bomberman.css" type="text/css" media="screen"/> <link rel="Stylesheet" href="/css/bomberman.css" type="text/css" media="screen"/>
<link rel="Stylesheet" href="/css/reset.css" type="text/css" media="screen"/> <link rel="Stylesheet" href="/css/reset.css" type="text/css" media="screen"/>
<link rel="Stylesheet" href="/css/typography.css" type="text/css" media="screen"/> <link rel="Stylesheet" href="/css/typography.css" type="text/css" media="screen"/>
Expand Down
3 changes: 2 additions & 1 deletion public/javascripts/game.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ MrJaba.Bomberman = function(){
} }


function restartMe(position){ function restartMe(position){
MrJaba.Bomberman.me.setTileX(parseInt(position.x)); MrJaba.Bomberman.me.setTileY(parseInt(position.y)) MrJaba.Bomberman.me.setTileX(parseInt(position.x)); MrJaba.Bomberman.me.setTileY(parseInt(position.y))
//alert(MrJaba.Bomberman.me.getX() + ' '+ MrJaba.Bomberman.me.getY());
MrJaba.Bomberman.GameClient.trigger('send_reset_state', "restart"); MrJaba.Bomberman.GameClient.trigger('send_reset_state', "restart");
} }


Expand Down
5 changes: 3 additions & 2 deletions public/javascripts/game_client.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ var GameClient = function(){
} }


var handleEvent = function(eventName, message){ var handleEvent = function(eventName, message){
console.log(eventName);
console.log($.dump(message));
var handler = callbacks[eventName]; var handler = callbacks[eventName];
if(typeof handler === undefined) return; if(typeof handler === undefined) return;
return handler(message); return handler(message);
Expand All @@ -58,8 +60,7 @@ var GameClient = function(){
this.trigger = function(eventName, data){ this.trigger = function(eventName, data){
var data = JSON.stringify({type:eventName, uuid:MrJaba.Bomberman.uuid , data:handleEvent(eventName, data) }); var data = JSON.stringify({type:eventName, uuid:MrJaba.Bomberman.uuid , data:handleEvent(eventName, data) });
console.log(eventName+' '+socket.readyState+' '+data); console.log(eventName+' '+socket.readyState+' '+data);
var result = socket.send(data); socket.send(data);
console.log(result);
}; };


initWebSocket(); initWebSocket();
Expand Down
165 changes: 165 additions & 0 deletions public/javascripts/jquery.dump.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,165 @@
/**
* jquery.dump.js
* @author Torkild Dyvik Olsen
* @version 1.0
*
* A simple debug function to gather information about an object.
* Returns a nested tree with information.
*
*/
(function($) {

$.fn.dump = function() {
return $.dump(this);
}

$.dump = function(object) {
var recursion = function(obj, level) {
if(!level) level = 0;
var dump = '', p = '';
for(i = 0; i < level; i++) p += "\t";

t = type(obj);
switch(t) {
case "string":
return '"' + obj + '"';
break;
case "number":
return obj.toString();
break;
case "boolean":
return obj ? 'true' : 'false';
case "date":
return "Date: " + obj.toLocaleString();
case "array":
dump += 'Array ( \n';
$.each(obj, function(k,v) {
dump += p +'\t' + k + ' => ' + recursion(v, level + 1) + '\n';
});
dump += p + ')';
break;
case "object":
dump += 'Object { \n';
$.each(obj, function(k,v) {
dump += p + '\t' + k + ': ' + recursion(v, level + 1) + '\n';
});
dump += p + '}';
break;
case "jquery":
dump += 'jQuery Object { \n';
$.each(obj, function(k,v) {
dump += p + '\t' + k + ' = ' + recursion(v, level + 1) + '\n';
});
dump += p + '}';
break;
case "regexp":
return "RegExp: " + obj.toString();
case "error":
return obj.toString();
case "document":
case "domelement":
dump += 'DOMElement [ \n'
+ p + '\tnodeName: ' + obj.nodeName + '\n'
+ p + '\tnodeValue: ' + obj.nodeValue + '\n'
+ p + '\tinnerHTML: [ \n';
$.each(obj.childNodes, function(k,v) {
if(k < 1) var r = 0;
if(type(v) == "string") {
if(v.textContent.match(/[^\s]/)) {
dump += p + '\t\t' + (k - (r||0)) + ' = String: ' + trim(v.textContent) + '\n';
} else {
r--;
}
} else {
dump += p + '\t\t' + (k - (r||0)) + ' = ' + recursion(v, level + 2) + '\n';
}
});
dump += p + '\t]\n'
+ p + ']';
break;
case "function":
var match = obj.toString().match(/^(.*)\(([^\)]*)\)/im);
match[1] = trim(match[1].replace(new RegExp("[\\s]+", "g"), " "));
match[2] = trim(match[2].replace(new RegExp("[\\s]+", "g"), " "));
return match[1] + "(" + match[2] + ")";
case "window":
default:
dump += 'N/A: ' + t;
break;
}

return dump;
}

var type = function(obj) {
var type = typeof(obj);

if(type != "object") {
return type;
}

switch(obj) {
case null:
return 'null';
case window:
return 'window';
case document:
return 'document';
case window.event:
return 'event';
default:
break;
}

if(obj.jquery) {
return 'jquery';
}

switch(obj.constructor) {
case Array:
return 'array';
case Boolean:
return 'boolean';
case Date:
return 'date';
case Object:
return 'object';
case RegExp:
return 'regexp';
case ReferenceError:
case Error:
return 'error';
case null:
default:
break;
}

switch(obj.nodeType) {
case 1:
return 'domelement';
case 3:
return 'string';
case null:
default:
break;
}

return 'Unknown';
}

return recursion(object);
}

function trim(str) {
return ltrim(rtrim(str));
}

function ltrim(str) {
return str.replace(new RegExp("^[\\s]+", "g"), "");
}

function rtrim(str) {
return str.replace(new RegExp("[\\s]+$", "g"), "");
}

})(jQuery);

0 comments on commit 2af9bb8

Please sign in to comment.