Using .json to configure the whole game

This commit is contained in:
Coeuvre 2014-05-26 10:22:06 +08:00
parent 9e61f10fc7
commit 8e72c0f1a7
6 changed files with 181 additions and 112 deletions

View file

@ -4,22 +4,25 @@ use piston::*;
use board::Board;
use number_renderer::NumberRenderer;
use settings::Settings;
pub struct App {
board: Board,
pub struct App<'a> {
board: Board<'a>,
number_renderer: Option<NumberRenderer>,
settings: &'a Settings,
}
impl App {
pub fn new() -> App {
impl<'a> App<'a> {
pub fn new(settings: &'a Settings) -> App<'a> {
App {
board: Board::new(),
board: Board::new(settings),
number_renderer: None,
settings: settings,
}
}
}
impl Game for App {
impl<'a> Game for App<'a> {
fn load(&mut self, asset_store: &mut AssetStore) {
self.number_renderer = Some(NumberRenderer::new(asset_store));
}
@ -50,7 +53,7 @@ impl Game for App {
self.board.merge_from_top_to_bottom();
}
if key == keyboard::Space {
self.board = Board::new();
self.board = Board::new(self.settings);
}
}

View file

@ -5,24 +5,27 @@ use rand::random;
use graphics::*;
use piston::*;
use number_renderer::NumberRenderer;
use settings;
use settings::Settings;
use tile::{
Tile,
TileStatic,
};
pub struct Board {
tiles: Vec<Tile>,
pub struct Board<'a> {
tiles: Vec<Tile<'a>>,
score: int,
highest_score: int,
settings: &'a Settings,
}
impl Board {
pub fn new() -> Board {
impl<'a> Board<'a> {
pub fn new(settings: &'a Settings) -> Board<'a> {
let mut board = Board {
tiles: Vec::<Tile>::new(),
score: 0,
highest_score: 0,
settings: settings,
};
board.generate_tile();
board.generate_tile();
@ -30,15 +33,15 @@ impl Board {
}
pub fn generate_tile(&mut self) {
if self.tiles.len() == (settings::TILE_WIDTH * settings::TILE_HEIGHT) as uint {
if self.tiles.len() == (self.settings.tile_width * self.settings.tile_height) as uint {
return;
}
loop {
let x = (random::<uint>() % settings::TILE_WIDTH as uint) as int;
let y = (random::<uint>() % settings::TILE_HEIGHT as uint) as int;
let x = (random::<uint>() % self.settings.tile_width as uint) as int;
let y = (random::<uint>() % self.settings.tile_height as uint) as int;
if self.get_tile(x, y).is_none() {
self.tiles.push(Tile::new(2, x, y));
self.tiles.push(Tile::new(self.settings, 2, x, y));
break;
}
}
@ -70,7 +73,7 @@ impl Board {
tiles_need_removed.insert(i);
tiles_need_removed.insert(j);
tiles_need_added.push(Tile::new_combined(tile1.score + tile2.score, tile1.tile_x, tile1.tile_y));
tiles_need_added.push(Tile::new_combined(self.settings, tile1.score + tile2.score, tile1.tile_x, tile1.tile_y));
score_to_added += tile1.score + tile2.score;
break;
}
@ -90,27 +93,32 @@ impl Board {
pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut Gl) {
c.view()
.rect(settings::BEST_RECT[0],
settings::BEST_RECT[1],
settings::BEST_RECT[2],
settings::BEST_RECT[3])
.rgba(settings::LABEL_COLOR[0],
settings::LABEL_COLOR[1],
settings::LABEL_COLOR[2],
settings::LABEL_COLOR[3])
.rect(self.settings.best_rect[0],
self.settings.best_rect[1],
self.settings.best_rect[2],
self.settings.best_rect[3])
.rgba(self.settings.label_color[0],
self.settings.label_color[1],
self.settings.label_color[2],
1.0)
.fill(gl);
number_renderer.render(self.score as u32, settings::BEST_RECT[0] + settings::BEST_RECT[2] / 2.0, settings::BEST_RECT[1] + settings::BEST_RECT[3] / 2.0, settings::BEST_RECT[2], settings::TEXT_LIGHT_COLOR, c, gl);
number_renderer.render(
self.score as u32,
self.settings.best_rect[0] + self.settings.best_rect[2] / 2.0,
self.settings.best_rect[1] + self.settings.best_rect[3] / 2.0,
self.settings.best_rect[2],
self.settings.text_light_color, c, gl);
self.render_board(c, gl);
self.render_tiles(number_renderer, c, gl);
}
pub fn merge_from_bottom_to_top(&mut self) {
self.merge_col(0, settings::TILE_HEIGHT, 1);
self.merge_col(0, self.settings.tile_height, 1);
}
pub fn merge_from_top_to_bottom(&mut self) {
self.merge_col(settings::TILE_HEIGHT - 1, -1, -1);
self.merge_col(self.settings.tile_height - 1, -1, -1);
}
fn merge_col(&mut self, y_start: int, y_end: int, y_step: int) {
@ -121,7 +129,7 @@ impl Board {
let mut need_generate = false;
loop {
// move all tiles to right place
for col in range(0, settings::TILE_WIDTH) {
for col in range(0, self.settings.tile_width) {
for row in range_step(y_start, y_end, y_step) {
match self.get_mut_tile(col, row) {
None => {
@ -141,7 +149,7 @@ impl Board {
}
let mut did_merged = false;
for col in range(0, settings::TILE_WIDTH) {
for col in range(0, self.settings.tile_width) {
let mut found = false;
let mut sx = 0;
let mut sy = 0;
@ -189,11 +197,11 @@ impl Board {
}
pub fn merge_from_left_to_right(&mut self) {
self.merge_row(settings::TILE_WIDTH - 1, -1, -1);
self.merge_row(self.settings.tile_width - 1, -1, -1);
}
pub fn merge_from_right_to_left(&mut self) {
self.merge_row(0, settings::TILE_WIDTH, 1);
self.merge_row(0, self.settings.tile_width, 1);
}
fn merge_row(&mut self, x_start: int, x_end: int, x_step: int) {
@ -204,7 +212,7 @@ impl Board {
let mut need_generate = false;
loop {
// move all tiles to right place
for row in range(0, settings::TILE_HEIGHT) {
for row in range(0, self.settings.tile_height) {
for col in range_step(x_start, x_end, x_step) {
match self.get_mut_tile(col, row) {
None => {
@ -224,7 +232,7 @@ impl Board {
// merge
let mut did_merged = false;
for row in range(0, settings::TILE_HEIGHT) {
for row in range(0, self.settings.tile_height) {
let mut found = false;
let mut sx = 0;
let mut sy = 0;
@ -282,11 +290,11 @@ impl Board {
}
/// Returns next tile right besides (x, y)
fn get_next_tile<'a>(&'a self, x: int, y: int, step_x: int, step_y: int) -> Option<&'a Tile> {
fn get_next_tile<'b>(&'b self, x: int, y: int, step_x: int, step_y: int) -> Option<&'b Tile<'a>> {
let mut x = x + step_x;
let mut y = y + step_y;
while x >= 0 && x < settings::TILE_WIDTH
&& y >= 0 && y < settings::TILE_HEIGHT {
while x >= 0 && x < self.settings.tile_width
&& y >= 0 && y < self.settings.tile_height {
let tile = self.get_tile(x, y);
if tile.is_some() {
return tile;
@ -297,12 +305,12 @@ impl Board {
None
}
fn get_mut_next_tile<'a>(&'a mut self, x: int, y: int, step_x: int, step_y: int) -> Option<&'a mut Tile> {
fn get_mut_next_tile<'b>(&'b mut self, x: int, y: int, step_x: int, step_y: int) -> Option<&'b mut Tile<'a>> {
let mut x = x + step_x;
let mut y = y + step_y;
let mut found = false;
while x >= 0 && x < settings::TILE_WIDTH
&& y >= 0 && y < settings::TILE_HEIGHT {
while x >= 0 && x < self.settings.tile_width
&& y >= 0 && y < self.settings.tile_height {
let tile = self.get_tile(x, y);
if tile.is_some() {
found = true;
@ -319,7 +327,7 @@ impl Board {
}
}
fn get_tile<'a>(&'a self, x: int, y: int) -> Option<&'a Tile> {
fn get_tile<'b>(&'b self, x: int, y: int) -> Option<&'b Tile<'a>> {
for tile in self.tiles.iter() {
if tile.tile_x == x && tile.tile_y == y {
return Some(tile);
@ -328,7 +336,7 @@ impl Board {
None
}
fn get_mut_tile<'a>(&'a mut self, x: int, y: int) -> Option<&'a mut Tile> {
fn get_mut_tile<'b>(&'b mut self, x: int, y: int) -> Option<&'b mut Tile<'a>> {
for tile in self.tiles.mut_iter() {
if tile.tile_x == x && tile.tile_y == y {
return Some(tile);
@ -349,32 +357,32 @@ impl Board {
fn render_board(&self, c: &Context, gl: &mut Gl) {
c.view()
.rect(settings::BOARD_PADDING,
settings::BOARD_PADDING + settings::BOARD_OFFSET_Y,
settings::BOARD_SIZE[0],
settings::BOARD_SIZE[1])
.rgba(settings::TILE_BACKGROUND_COLOR[0],
settings::TILE_BACKGROUND_COLOR[1],
settings::TILE_BACKGROUND_COLOR[2],
settings::TILE_BACKGROUND_COLOR[3])
.rect(self.settings.board_padding,
self.settings.board_padding + self.settings.board_offset_y,
self.settings.board_size[0],
self.settings.board_size[1])
.rgba(self.settings.tile_background_color[0],
self.settings.tile_background_color[1],
self.settings.tile_background_color[2],
1.0)
.fill(gl);
let mut x = settings::BOARD_PADDING + settings::TILE_PADDING;
let mut y = settings::BOARD_PADDING + settings::BOARD_OFFSET_Y + settings::TILE_PADDING;
for _ in range(0, settings::TILE_HEIGHT) {
for _ in range(0, settings::TILE_WIDTH) {
let mut x = self.settings.board_padding + self.settings.tile_padding;
let mut y = self.settings.board_padding + self.settings.board_offset_y + self.settings.tile_padding;
for _ in range(0, self.settings.tile_height) {
for _ in range(0, self.settings.tile_width) {
c.view()
.rect(x, y, settings::TILE_SIZE, settings::TILE_SIZE)
.rgba(settings::TILES_COLOR[0][0],
settings::TILES_COLOR[0][1],
settings::TILES_COLOR[0][2],
settings::TILES_COLOR[0][3])
.rect(x, y, self.settings.tile_size, self.settings.tile_size)
.rgba(self.settings.tiles_colors.get(0)[0],
self.settings.tiles_colors.get(0)[1],
self.settings.tiles_colors.get(0)[2],
1.0)
.fill(gl);
x += settings::TILE_PADDING + settings::TILE_SIZE;
x += self.settings.tile_padding + self.settings.tile_size;
}
x = settings::BOARD_PADDING + settings::TILE_PADDING;
y += settings::TILE_PADDING + settings::TILE_SIZE;
x = self.settings.board_padding + self.settings.tile_padding;
y += self.settings.tile_padding + self.settings.tile_size;
}
}

View file

@ -19,21 +19,24 @@ mod tile;
type GameWindowBackEnd = GameWindowSDL2;
fn main() {
let settings = settings::SettingsInJson::load();
let settings = settings::Settings::load();
let mut game_window: GameWindowBackEnd = GameWindow::new(
GameWindowSettings::new (
"Rust-2048".to_owned(),
settings::WINDOW_SIZE,
settings.window_size,
false,
true,
settings::WINDOW_BACKGROUND_COLOR,
[settings.window_background_color[0],
settings.window_background_color[1],
settings.window_background_color[2],
1.0,],
)
);
let mut asset_store = AssetStore::from_folder(settings::ASSET_FOLDER);
let mut asset_store = AssetStore::from_folder(settings.asset_folder.as_slice());
let mut app = app::App::new();
let mut app = app::App::new(&settings);
app.run(&mut game_window, &mut asset_store);
}

View file

@ -20,7 +20,7 @@ impl NumberRenderer {
}
pub fn render(&self, number: u32, center_x: f64, center_y: f64, max_width: f64,
color: [f32, ..4], c: &Context, gl: &mut Gl) {
color: [f32, ..3], c: &Context, gl: &mut Gl) {
let digits = number_to_digits(number);
let total_width = DIGITS_WIDTH * digits.len() as f64;
let total_width = if total_width > max_width {
@ -38,7 +38,7 @@ impl NumberRenderer {
for digit in digits.iter() {
image.source_rect[0] = DIGITS_WIDTH as u32 * *digit;
c.view().rect(x, y, width, height)
.image(image).rgba(color[0], color[1], color[2], color[3])
.image(image).rgba(color[0], color[1], color[2], 1.0)
.draw(gl);
x += width;
}

View file

@ -8,6 +8,7 @@ use serialize::{
Decodable,
};
/*
pub static ASSET_FOLDER: &'static str = "assets";
pub static WINDOW_SIZE: [u32, ..2] = [
@ -63,7 +64,7 @@ pub static BUTTON_COLOR: [f32, ..4] = [142.0 / 255.0, 122.0 / 255.0, 102.0 / 255
pub static TEXT_DARK_COLOR: [f32, ..4] = [119.0 / 255.0, 110.0 / 255.0, 101.0 / 255.0, 1.0];
pub static TEXT_LIGHT_COLOR: [f32, ..4] = [249.0 / 255.0, 246.0 / 255.0, 242.0 / 255.0, 1.0];
*/
static SETTING_FILENAME: &'static str = "settings.json";
@ -93,10 +94,6 @@ pub struct Settings {
}
impl Settings {
pub fn default_settings() -> Settings {
Settings::from_settings_in_json(&SettingsInJson::default_settings())
}
pub fn load() -> Settings {
Settings::from_settings_in_json(&SettingsInJson::load())
}
@ -107,16 +104,25 @@ impl Settings {
s.tile_size * s.tile_height as f64 + s.tile_padding * (s.tile_height + 1) as f64,
];
let mut tiles_colors = Vec::<[f32, ..3]>::new();
for color in s.tiles_colors.iter() {
tiles_colors.push([
*color.get(0) / 255.0,
*color.get(1) / 255.0,
*color.get(2) / 255.0,
]);
}
Settings {
asset_folder: s.asset_folder,
asset_folder: s.asset_folder.clone(),
window_size: [
(s.board_padding * 2.0 + board_size[0]) as u32,
(s.board_padding * 2.0 + board_size[1] + s.board_offset_y) as u32,
],
window_background_color: [
*s.window_background_color.get(0),
*s.window_background_color.get(1),
*s.window_background_color.get(2),
*s.window_background_color.get(0) / 255.0,
*s.window_background_color.get(1) / 255.0,
*s.window_background_color.get(2) / 255.0,
],
board_padding: s.board_padding,
board_size: board_size,
@ -126,9 +132,50 @@ impl Settings {
tile_size: s.tile_size,
tile_padding: s.tile_padding,
tile_background_color: [
*s.tile_background_color.get(0),
*s.tile_background_color.get(1),
*s.tile_background_color.get(2),
*s.tile_background_color.get(0) / 255.0,
*s.tile_background_color.get(1) / 255.0,
*s.tile_background_color.get(2) / 255.0,
],
tiles_colors: tiles_colors,
tile_unknow_color: [
*s.tile_unknow_color.get(0) / 255.0,
*s.tile_unknow_color.get(1) / 255.0,
*s.tile_unknow_color.get(2) / 255.0,
],
tile_move_time: s.tile_move_time,
tile_new_time: s.tile_new_time,
tile_combine_time: s.tile_combine_time,
best_rect: [
*s.best_rect.get(0),
*s.best_rect.get(1),
*s.best_rect.get(2),
*s.best_rect.get(3),
],
score_rect: [
*s.score_rect.get(0),
*s.score_rect.get(1),
*s.score_rect.get(2),
*s.score_rect.get(3),
],
label_color: [
*s.label_color.get(0) / 255.0,
*s.label_color.get(1) / 255.0,
*s.label_color.get(2) / 255.0,
],
button_color: [
*s.button_color.get(0) / 255.0,
*s.button_color.get(1) / 255.0,
*s.button_color.get(2) / 255.0,
],
text_dark_color: [
*s.text_dark_color.get(0) / 255.0,
*s.text_dark_color.get(1) / 255.0,
*s.text_dark_color.get(2) / 255.0,
],
text_light_color: [
*s.text_light_color.get(0) / 255.0,
*s.text_light_color.get(1) / 255.0,
*s.text_light_color.get(2) / 255.0,
],
}
}
@ -196,7 +243,7 @@ impl SettingsInJson {
tile_width: 4,
tile_height: 4,
tile_size: 72.0,
tile_padding: 12.0,
tile_padding: 16.0,
tile_background_color: vec![187.0, 173.0, 160.0],
tiles_colors: tiles_colors,
tile_unknow_color: vec![200.0, 0.0, 0.0],
@ -220,7 +267,9 @@ impl SettingsInJson {
let exe_path = exe_path.unwrap();
let path = exe_path.join(Path::new(SETTING_FILENAME));
if !path.exists() || !path.is_file() {
return SettingsInJson::default_settings();
let default = SettingsInJson::default_settings();
default.save();
return default;
}
let file = File::open(&path).unwrap();
let mut reader = BufferedReader::new(file);

View file

@ -2,7 +2,7 @@
use graphics::*;
use piston::*;
use number_renderer::NumberRenderer;
use settings;
use settings::Settings;
#[deriving(Clone, Eq)]
pub enum TileState {
@ -16,49 +16,55 @@ pub enum TileState {
}
#[deriving(Clone)]
pub struct Tile {
pub struct Tile<'a> {
pub score: int,
pub tile_x: int,
pub tile_y: int,
pub status: TileState,
settings: &'a Settings,
}
impl Tile {
pub fn new(score: int, tile_x: int, tile_y: int) -> Tile {
impl<'a> Tile<'a> {
pub fn new(settings: &'a Settings, score: int, tile_x: int, tile_y: int) -> Tile<'a> {
Tile {
score: score,
tile_x: tile_x,
tile_y: tile_y,
status: TileNew(settings::TILE_NEW_TIME, 0.0),
status: TileNew(settings.tile_new_time, 0.0),
settings: settings,
}
}
pub fn new_combined(score: int, tile_x: int, tile_y: int) -> Tile {
pub fn new_combined(settings: &'a Settings, score: int, tile_x: int, tile_y: int) -> Tile<'a> {
Tile {
score: score,
tile_x: tile_x,
tile_y: tile_y,
status: TileCombine(settings::TILE_COMBINE_TIME, 1.2 * settings::TILE_SIZE),
status: TileCombine(settings.tile_combine_time, 1.2 * settings.tile_size),
settings: settings,
}
}
fn tile_to_pos(tile_x: int, tile_y: int) -> (f64, f64) {
let x = settings::BOARD_PADDING + tile_x as f64 * settings::TILE_SIZE + (tile_x + 1) as f64 * settings::TILE_PADDING;
let y = settings::BOARD_PADDING + settings::BOARD_OFFSET_Y + tile_y as f64 * settings::TILE_SIZE + (tile_y + 1) as f64 * settings::TILE_PADDING;
fn tile_to_pos(&self, tile_x: int, tile_y: int) -> (f64, f64) {
let x = self.settings.board_padding + tile_x as f64 * self.settings.tile_size + (tile_x + 1) as f64 * self.settings.tile_padding;
let y = self.settings.board_padding + self.settings.board_offset_y + tile_y as f64 * self.settings.tile_size + (tile_y + 1) as f64 * self.settings.tile_padding;
(x, y)
}
pub fn start_moving(&mut self, destination_tile_x: int, destination_tile_y: int) {
match self.status {
TileMoving(_, _, _, ox, oy) => {
let (x, y) = Tile::tile_to_pos(ox, oy);
self.status = TileMoving(settings::TILE_MOVE_TIME, x, y, ox, oy);
let (x, y) = self.tile_to_pos(ox, oy);
self.status = TileMoving(self.settings.tile_move_time, x, y, ox, oy);
self.tile_x = destination_tile_x;
self.tile_y = destination_tile_y;
},
TileStatic => {
let (x, y) = Tile::tile_to_pos(self.tile_x, self.tile_y);
self.status = TileMoving(settings::TILE_MOVE_TIME, x, y, self.tile_x, self.tile_y);
let (x, y) = self.tile_to_pos(self.tile_x, self.tile_y);
self.status = TileMoving(self.settings.tile_move_time, x, y, self.tile_x, self.tile_y);
self.tile_x = destination_tile_x;
self.tile_y = destination_tile_y;
},
@ -72,7 +78,7 @@ impl Tile {
if dt >= t {
self.status = TileStatic;
} else {
let (dx, dy) = Tile::tile_to_pos(self.tile_x, self.tile_y);
let (dx, dy) = self.tile_to_pos(self.tile_x, self.tile_y);
let factor = dt / t;
self.status = TileMoving(t - dt, x + factor * (dx - x), y + factor * (dy - y), ox, oy);
}
@ -82,7 +88,7 @@ impl Tile {
self.status = TileStatic;
} else {
let factor = dt / t;
self.status = TileNew(t - dt, size + factor * (settings::TILE_SIZE - size));
self.status = TileNew(t - dt, size + factor * (self.settings.tile_size - size));
}
},
TileCombine(t, size) => {
@ -90,7 +96,7 @@ impl Tile {
self.status = TileStatic;
} else {
let factor = dt / t;
self.status = TileCombine(t - dt, size + factor * (settings::TILE_SIZE - size));
self.status = TileCombine(t - dt, size + factor * (self.settings.tile_size - size));
}
},
_ => {},
@ -98,8 +104,8 @@ impl Tile {
}
pub fn render(&self, number_renderer: &NumberRenderer, c: &Context, gl: &mut Gl) {
let mut pos = Tile::tile_to_pos(self.tile_x, self.tile_y);
let mut size = (settings::TILE_SIZE, settings::TILE_SIZE);
let mut pos = self.tile_to_pos(self.tile_x, self.tile_y);
let mut size = (self.settings.tile_size, self.settings.tile_size);
match self.status {
TileMoving(_, x, y, _, _) => {
pos = (x, y);
@ -116,25 +122,25 @@ impl Tile {
let (w, h) = size;
let color = self.get_color();
c.view()
.rect_centered(x + settings::TILE_SIZE / 2.0,
y + settings::TILE_SIZE / 2.0,
.rect_centered(x + self.settings.tile_size / 2.0,
y + self.settings.tile_size / 2.0,
w / 2.0, h / 2.0)
.rgba(color[0], color[1], color[2], color[3]).fill(gl);
.rgba(color[0], color[1], color[2], 1.0).fill(gl);
let color = if self.score >= 8 {
settings::TEXT_LIGHT_COLOR
self.settings.text_light_color
} else {
settings::TEXT_DARK_COLOR
self.settings.text_dark_color
};
number_renderer.render(self.score as u32, x + settings::TILE_SIZE / 2.0, y + settings::TILE_SIZE / 2.0, settings::TILE_SIZE, color, c, gl);
number_renderer.render(self.score as u32, x + self.settings.tile_size / 2.0, y + self.settings.tile_size / 2.0, self.settings.tile_size, color, c, gl);
}
fn get_color(&self) -> [f32, ..4] {
fn get_color(&self) -> [f32, ..3] {
let i = (self.score as f64).log2() as uint;
if i > 0 && i < settings::TILES_COLOR.len() {
settings::TILES_COLOR[i]
if i > 0 && i < self.settings.tiles_colors.len() {
*self.settings.tiles_colors.get(i)
} else {
settings::TILE_UNKNOW_COLOR
self.settings.tile_unknow_color
}
}
}