johnthagen / rust-belt Goto Github PK
View Code? Open in Web Editor NEW:rocket: Asteroids-like arcade game implemented in Rust ✨
:rocket: Asteroids-like arcade game implemented in Rust ✨
Determine easiest way to install GCC on Windows to easily build Piston projects.
It would be neat to be able to change the window resolution in the Settings page.
Piston has a built in size type: http://docs.piston.rs/piston/window/struct.Size.html
We shouldn't recreate this ourselves.
We'll soon have different types of models (#5 , #14, etc) and the current structure of having all nine modules at the top level is starting to feel a little disorganized. I think it would be worth getting this organized before the weapon is started (#5).
rocket
organizes its structure like:
main.rs
game.rs
drawing/
point.rs
...
models/
bullet.rs
player.rs
...
traits/
rust-belt
will be a little different because we have a menu that sits above our game.
A rough sketch:
main.rs
menu/
game/
models/
player.rs
bullet, enemy, etc
mod.rs (Drawable, Updateable)
drawing/
mod.rs (color, Vector, Point, etc?)
mod.rs (Game)
mod.rs (Menu)
story.rs
settings.rs
@mcdenhoed, @theandrewdavis any thoughts on this? I'm unsure if the menu/
top level directory is necessary, but seemed to model how the game is currently structured.
Currently Game
creates it's own copy of the GlyphCache
due to lifetime issues I ran into. Ideally this should be passed into the Game
constructor from menu
, or at least clone()
'd.
It's grown quite a bit and is now most of models/mod.rs
.
What is the best way to play short sound effects? Best I could find is using rust-sdl2
directly (piston-music
actually wraps this). Not sure the ramifications of trying to use both libraries at once.
Sound effects:
The original asteroid games had lives, would be cool to implement something similar (maybe just shields that take so many collisions before you lose the game).
In the player
module, we have Vect
which is an x, y coordinate. I think we'll quickly want to enhance this to also include velocity so it can be shared by Bullet
's, Asteroids
, etc.
rocket
does:
/// A `Point` represents a position in space
#[derive(Clone, Default)]
pub struct Point {
pub x: f64,
pub y: f64
}
...
/// A `Vector`
#[derive(Clone, Default)]
pub struct Vector {
/// The position of the vector
pub position: Point,
/// The direction angle, in radians
pub direction: f64
}
To me this seems pretty optimal. @mcdenhoed, what do you think?
It would be neat if it were, for example, possible to find Kara, perhaps then providing a boost to weapons, shields, etc.
Currently if a player were to spin in the same direction constantly, rot
will grow unbounded. We should "mod" the value by 2PI
similar to how we mod the position of the player.
Especially since there is some non-trivial math in there (like getting the average center of the asteroid) we should document the functions and methods.
fn randomize_shape(mut shape: CircularPolygon, max: f64) -> CircularPolygon {
let mut average_x = 0.0;
let mut average_y = 0.0;
Could be a little more readable be creating a single Vector
and using average.x
, average.y
.
Vector
should probably also #[derive(Default)]
so that the manual assignment to 0.0
is not needed.
It would be nice to document Ubuntu install instructions to have a Linux install example.
It's probably just something like sudo apt-get install libsdl2-dev libsdl2-mixer-dev
Player
See https://crates.io/crates/rand
See
Probably need to use AppVeyor until Travis supports Windows.
Possible source of inspiration: https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml
Score could be (inversely) based on the radius of the asteroid destroyed.
There are a lot of const
module variables that are only used in a single function. To reduce the scope of these variables and keep the module namespaces tidy, we should move them into their respective functions.
The original Asteroids used lines to draw objects rather than filled polygons (perhaps that was a limitation of the day?). It might be interesting to use lines
ourselves for some objects.
I think it's possible for an Asteroid
to never make it onto the screen if it spawns in a corner and never gets its radius fully into the screen.
Then I think it enters a black hole where it's flying around taking up resources but can't be shot.
Ideally, we shouldn't have lots of current text()
calls in a closure that all mostly pass the same arguments.
Right now, asteroids are spawned within the window, causing them to appear instantly.
We should modify them so that they are spawned OUTSIDE the window and then can drift in. Once they have drifted in, we can have their position wrap like it does now.
As a side-effect this should alleviate (to some degree) the issue of an asteroid spawning on a player.
Per #97 (comment), it would be a bit more consistent if we used the Drawable
trait on Game
rather than having a draw
method hanging out in the impl
.
Since Drawable::draw
doesn't take the GlypheCache
, we'll need to pass it into the constructor of Game
so it's available in self
.
I worked on this a little bit, but hit some lifetime struggles, but it was the first time I had ever tried using lifetimes.
The Windows Install instructions say to add the SDL .lib files to the LIB system path. My system (64-bit Windows 10) does not have a LIB environment variable in either the user or the system menu. Do I create this env var if it doesn't exist?
See: https://github.com/johnthagen/rocket/blob/master/src/main.rs#L64
This should allow for consistent reaction to buttons regardless if there is variability in the actual frame rate or update cycle speed.
Be sure to also remove the #[allow(unused_variables)]
from Game::run
.
One idea is thatrocket
uses a World
to keep track of all of the different entities that exist at any moment: https://github.com/aochagavia/rocket/blob/master/src/models/world.rs#L9
Now that other objects within Game
other than player
need to know the size of the Window (like asteroids #7 and Bullet
s), we should store a copy within Game
and use that as the ground truth that is passed to all other objects.
We'll want something generic since we'll need it for at least weapon bullets, asteroids, and the player.
I think the wrap
function would be cleaner if rather than mutating a reference, to k
it simply returned the wrapped result.
https://github.com/johnthagen/rust-belt/blob/master/src/game.rs#L41
Integrate rust-clippy into build.
Unfortunately it looks as if rust-clippy
will require Unstable nightly rustc
for the foreseeable future, though it looks like eventually it will be distributed with rustup
.
When the player gets hit by an asteroid, the game immediately goes back to the main menu. It might be nice to instead go to a game-over screen displaying the player's score, and from there go to the menu. Could even display local high scores there.
We have the following code in (soon to be) three places:
let x = self.pos.x + self.vel.x + self.window_size.width as f64;
let y = self.pos.y + self.vel.y + self.window_size.height as f64;
self.pos.x = x % self.window_size.width as f64;
self.pos.y = y % self.window_size.height as f64;
It would be good to refactor this into some kind of trait or function that can be shared between Updateable
types. Perhaps a sub-trait of Updateable
, something like Movable
could expose pos()
and vel()
.
Potentially we could simplify this with the new Vector::add()
as well instead of treating x
and y
separately.
See: PistonDevelopers/piston_window#186 (comment)
Another thing: I see you use the ellipse shortcut: This uses the default resolution 128 which is very high
A few trivial clippy
lint problems were found, see: https://travis-ci.org/johnthagen/rust-belt/jobs/192171369
The command "cargo build --verbose" exited with 0.
1.04s$ bash -c 'if [[ "$TRAVIS_RUST_VERSION" == "nightly-2017-01-13" ]]; then cargo clippy -- -D warnings; fi'
Compiling rust-belt v0.4.0 (file:///home/travis/build/johnthagen/rust-belt)
error: manual implementation of an assign operation [-D assign-op-pattern]
--> src/settings.rs:44:33
|
44 | Key::D => { *volume = *volume + VOLUME_STEP }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with
| Key::D => { *volume += VOLUME_STEP }
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern
error: manual implementation of an assign operation [-D assign-op-pattern]
--> src/settings.rs:45:33
|
45 | Key::A => { *volume = *volume - VOLUME_STEP }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with
| Key::A => { *volume -= VOLUME_STEP }
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#assign_op_pattern
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` [-D single-match]
--> src/story.rs:124:17
|
124 | match key {
| _________________^ starting here...
125 | | Key::Space => { break }
126 | | _ => {}
127 | | }
| |_________________^ ...ending here
|
help: try this
| if let Key::Space = key { break }
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#single_match
See: https://github.com/johnthagen/rocket/blob/master/src/game.rs#L53
Basically we need to track when keys are pressed and released rather than when they are pressed calling a translation function directly.
Currently information about how the player's ship is drawn is located in the game
module (For example the SHIP
triangle
).
Pretty soon (#5, #7, etc) we will be having a lot more entities on the screen. How should the way those entities are drawn be encapsulated?
rocket
has a draw
method on all of its drawable models. I think this is a pretty good strategy. For example, when #28 is implemented, there will be multiple different things being drawn to the screen for the player (boosters in different directions) depending on the state of the Player
.
I propose a Drawable
trait that Player
, Bullet
, Asteroid
, (even Game
?) could implement that exposes a draw
method.
/// Draws the entity to the screen.
fn draw(&self, c: &Context, gl: &mut GlGraphics);
If it works out well, we could even contribute something like it back to rocket
.
@mcdenhoed, @theandrewdavis, any thoughts?
OSX builds seem to fail often, and we really don't need as many of them as we run (especially the nightly ones).
Overall, trim out the unnecessary builds.
Once Travis is passing again from #31, should bump the version of nightly and clippy used in Travis.
It would be nice to re-brand the rust belt MP3s with a consistent logo with the Github page.
The image should be 1x1 aspect ratio with some discussion here: https://www.blisshq.com/music-library-management-blog/2011/12/05/whats-the-best-album-art-size/
The following code in Asteroid
looks like it could be the basis for a common drawing default implementation that could be shared by most modules rather than being duplicated:
fn draw(&self, context: Context, graphics: &mut GlGraphics) {
polygon(color::WHITE,
&self.shape,
context.transform
.trans(self.pos.x, self.pos.y)
.rot_rad(self.rot),
graphics)
}
Note that the key pieces of information that are needed by the "derived" type would be:
color()
shape()
pos()
rot()
Then the Drawable
trait (or perhaps a derived trait so that you could just still use Drawable
without having to necessarily conform to the full specific interface that gives the nice default implementation) would implement something like:
fn draw(&self, context: Context, graphics: &mut GlGraphics) {
polygon(self.color(),
&self.shape(),
context.transform
.trans(self.pos().x, self.pos().y)
.rot_rad(self.rot()),
graphics)
}
Relates to #52
Several types now have a lot of pub
members. Should reevaluate if we really want to expose both read and write to these members or if we should have get-only methods. It's possible there could be a shared trait for some of these getters (such as position and velocity) that multiple models could use.
CC @theandrewdavis and @mcdenhoed for any input.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.