#[repr(C)]pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
Expand description
Utility type for manpulating RGBA colors
Color
is a simple color type composed of 4 components: Red, Green, Blue, Alpha
§Example
There are 3 basic ways to construct a color
use sfml::graphics::Color;
let color1 = Color::rgb(255, 0, 0); // from red/green/blue values
let color2 = Color::rgba(255, 255, 255, 128); // from red/green/blue/alpha (transparency)
let color3 = Color::GREEN; // from one of the associated color constants
Fields§
§r: u8
Red component
g: u8
Green component
b: u8
Blue component
a: u8
Alpha component (transparency)
Implementations§
Source§impl Color
impl Color
Sourcepub const TRANSPARENT: Self
pub const TRANSPARENT: Self
Tranparent predefined color
Sourcepub const fn rgb(red: u8, green: u8, blue: u8) -> Self
pub const fn rgb(red: u8, green: u8, blue: u8) -> Self
Construct a color from its 3 RGB components
§Arguments
- red - Red component (0 .. 255)
- green - -Green component (0 .. 255)
- blue - Blue component (0 .. 255)
Return Color object constructed from the components
Examples found in repository?
examples/custom-shape.rs (line 43)
28fn hue_time(t: f32) -> Color {
29 const fn lerp(from: f32, to: f32, amount: f32) -> f32 {
30 from + amount * (to - from)
31 }
32
33 let frac = t.fract();
34
35 let [r, g, b] = match (t % 6.0).floor() {
36 0.0 => [255., lerp(0., 255., frac), 0.],
37 1.0 => [lerp(255., 0., frac), 255., 0.],
38 2.0 => [0., 255., lerp(0., 255., frac)],
39 3.0 => [0., lerp(255., 0., frac), 255.],
40 4.0 => [lerp(0., 255., frac), 0., 255.],
41 _ => [255., 0., lerp(255., 0., frac)],
42 };
43 Color::rgb(r as u8, g as u8, b as u8)
44}
More examples
examples/shader.rs (line 142)
131 fn new() -> SfResult<Self> {
132 use rand::{thread_rng, Rng};
133 let mut rng = thread_rng();
134
135 let mut points = Vec::new();
136 for _ in 0..40_000 {
137 let x = rng.gen_range(0.0..800.);
138 let y = rng.gen_range(0.0..600.);
139 let (red, green, blue) = (rng.r#gen(), rng.r#gen(), rng.r#gen());
140 points.push(Vertex::with_pos_color(
141 Vector2f::new(x, y),
142 Color::rgb(red, green, blue),
143 ));
144 }
145
146 let shader = Shader::from_file_vert_frag("storm.vert", "blink.frag")?;
147 Ok(Self { points, shader })
148 }
149}
150
151impl Drawable for StormBlink {
152 fn draw<'a: 'shader, 'texture, 'shader, 'shader_texture>(
153 &'a self,
154 target: &mut dyn RenderTarget,
155 states: &RenderStates<'texture, 'shader, 'shader_texture>,
156 ) {
157 let mut states = *states;
158 states.shader = Some(&self.shader);
159 target.draw_primitives(&self.points, PrimitiveType::POINTS, &states);
160 }
161}
162
163impl Effect for StormBlink {
164 fn update(&mut self, t: f32, x: f32, y: f32) -> SfResult<()> {
165 let radius = 200. + t.cos() * 150.;
166 self.shader
167 .set_uniform_vec2("storm_position", Vector2f::new(x * 800., y * 600.))?;
168 self.shader
169 .set_uniform_float("storm_inner_radius", radius / 3.)?;
170 self.shader
171 .set_uniform_float("storm_total_radius", radius)?;
172 self.shader
173 .set_uniform_float("blink_alpha", 0.5 + (t * 3.).cos() * 0.25)
174 }
175 fn name(&self) -> &str {
176 "storm + blink"
177 }
178 fn as_drawable(&self) -> &dyn Drawable {
179 self
180 }
181}
182
183struct Edge<'t> {
184 surface: FBox<RenderTexture>,
185 bg_sprite: Sprite<'t>,
186 entities: Vec<Sprite<'t>>,
187 shader: FBox<Shader<'static>>,
188}
189
190impl<'t> Edge<'t> {
191 fn new(bg_texture: &'t Texture, entity_texture: &'t Texture) -> SfResult<Self> {
192 let mut surface = RenderTexture::new(800, 600)?;
193 surface.set_smooth(true);
194 let mut bg_sprite = Sprite::with_texture(bg_texture);
195 bg_sprite.set_position((135., 100.));
196 let mut entities = Vec::new();
197
198 for i in 0..6 {
199 entities.push(Sprite::with_texture_and_rect(
200 entity_texture,
201 IntRect::new(96 * i, 0, 96, 96),
202 ));
203 }
204
205 let mut shader = Shader::from_file("edge.frag", ShaderType::Fragment)?;
206 shader.set_uniform_current_texture("texture")?;
207
208 Ok(Self {
209 surface,
210 bg_sprite,
211 entities,
212 shader,
213 })
214 }
215}
216
217impl Drawable for Edge<'_> {
218 fn draw<'a: 'shader, 'texture, 'shader, 'shader_texture>(
219 &'a self,
220 target: &mut dyn RenderTarget,
221 states: &RenderStates<'texture, 'shader, 'shader_texture>,
222 ) {
223 let mut states = *states;
224 states.shader = Some(&self.shader);
225 target.draw_with_renderstates(&Sprite::with_texture(self.surface.texture()), &states);
226 }
227}
228
229impl Effect for Edge<'_> {
230 fn update(&mut self, t: f32, x: f32, y: f32) -> SfResult<()> {
231 self.shader
232 .set_uniform_float("edge_threshold", 1. - (x + y) / 2.)?;
233 let entities_len = self.entities.len() as f32;
234
235 for (i, en) in self.entities.iter_mut().enumerate() {
236 let pos = (
237 (0.25 * (t * i as f32 + (entities_len - i as f32))).cos() * 300. + 350.,
238 (0.25 * (t * (entities_len - i as f32) + i as f32)).cos() * 200. + 250.,
239 );
240 en.set_position(pos);
241 }
242 self.surface.clear(Color::WHITE);
243 self.surface.draw(&self.bg_sprite);
244 for en in &self.entities {
245 self.surface.draw(en);
246 }
247 self.surface.display();
248 Ok(())
249 }
250 fn as_drawable(&self) -> &dyn Drawable {
251 self
252 }
253 fn name(&self) -> &str {
254 "edge post-effect"
255 }
256}
257
258fn main() -> SfResult<()> {
259 example_ensure_right_working_dir();
260
261 let mut window = RenderWindow::new(
262 (800, 600),
263 "SFML Shader",
264 Style::TITLEBAR | Style::CLOSE,
265 &Default::default(),
266 )?;
267 window.set_vertical_sync_enabled(true);
268 let font = Font::from_file("sansation.ttf")?;
269 let bg = Texture::from_file("background.jpg")?;
270 let mut bg_texture = Texture::from_file("sfml.png")?;
271 bg_texture.set_smooth(true);
272 let mut entity_texture = Texture::from_file("devices.png")?;
273 entity_texture.set_smooth(true);
274 let effects: [&mut dyn Effect; 4] = [
275 &mut Pixelate::new(&bg)?,
276 &mut WaveBlur::new(&font)?,
277 &mut StormBlink::new()?,
278 &mut Edge::new(&bg_texture, &entity_texture)?,
279 ];
280 let mut current = 0;
281 let text_bg_texture = Texture::from_file("text-background.png")?;
282 let mut text_bg = Sprite::with_texture(&text_bg_texture);
283 text_bg.set_position((0., 520.));
284 text_bg.set_color(Color::rgba(255, 255, 255, 200));
285 let msg = format!("Current effect: {}", effects[current].name());
286 let mut desc = Text::new(&msg, &font, 20);
287 desc.set_position((10., 530.));
288 desc.set_fill_color(Color::rgb(80, 80, 80));
289 let msg = "Press left and right arrows to change the current shader";
290 let mut instructions = Text::new(msg, &font, 20);
291 instructions.set_position((280., 555.));
292 instructions.set_fill_color(Color::rgb(80, 80, 80));
293 let clock = Clock::start()?;
294
295 while window.is_open() {
296 while let Some(event) = window.poll_event() {
297 use crate::Event::*;
298 match event {
299 Closed => window.close(),
300 KeyPressed { code, .. } => match code {
301 Key::Escape => window.close(),
302 Key::Left => {
303 if current == 0 {
304 current = effects.len() - 1;
305 } else {
306 current -= 1;
307 }
308 desc.set_string(&format!("Current effect: {}", effects[current].name()));
309 }
310 Key::Right => {
311 if current == effects.len() - 1 {
312 current = 0;
313 } else {
314 current += 1;
315 }
316 desc.set_string(&format!("Current effect: {}", effects[current].name()));
317 }
318 _ => {}
319 },
320 _ => {}
321 }
322 }
323
324 let x = window.mouse_position().x as f32 / window.size().x as f32;
325 let y = window.mouse_position().y as f32 / window.size().y as f32;
326
327 effects[current].update(clock.elapsed_time().as_seconds(), x, y)?;
328
329 window.clear(Color::rgb(255, 128, 0));
330 window.draw(effects[current].as_drawable());
331 window.draw(&text_bg);
332 window.draw(&instructions);
333 window.draw(&desc);
334 window.display();
335 }
336 Ok(())
337}
examples/custom-sound-recorder.rs (line 197)
65fn main() -> Result<(), Box<dyn Error>> {
66 example_ensure_right_working_dir();
67
68 assert!(
69 capture::is_available(),
70 "Sorry, audio capture is not supported by your system"
71 );
72 let default_device = capture::default_device();
73 let devices = capture::available_devices();
74 let mut rw = RenderWindow::new(
75 (800, 600),
76 "Custom sound recorder",
77 Style::CLOSE,
78 &Default::default(),
79 )?;
80 rw.set_vertical_sync_enabled(true);
81 let font = Font::from_file("sansation.ttf")?;
82 let (mut rec, recv) = MyRecorder::new();
83 let mut samp_buf = Vec::new();
84 let mut driver = SoundRecorderDriver::new(&mut rec);
85 let mut started = false;
86 let mut snd_buf = SoundBuffer::new()?;
87 let mut samp_accum = Vec::new();
88 let mut sound = Some(Sound::new());
89 let mut selected_dev_idx = 0;
90 let mut mode = Mode::Main;
91 let mut input_buf = String::new();
92 let mut desired_sample_rate = 44_100;
93 let mut desired_channel_count = 2;
94
95 while rw.is_open() {
96 while let Some(ev) = rw.poll_event() {
97 match ev {
98 Event::Closed => rw.close(),
99 Event::KeyPressed { code, .. } => match mode {
100 Mode::Main => match code {
101 Key::R => {
102 if started {
103 driver.stop();
104 sound = None;
105 snd_buf.load_from_samples(
106 &samp_accum[..],
107 desired_channel_count,
108 desired_sample_rate,
109 )?;
110 samp_accum.clear();
111 started = false;
112 } else {
113 driver.set_device(devices[selected_dev_idx].to_str()?)?;
114 driver.set_channel_count(desired_channel_count);
115 driver.start(desired_sample_rate)?;
116 started = true;
117 }
118 }
119 Key::P => {
120 if !started {
121 let sound = sound.insert(Sound::with_buffer(&snd_buf));
122 sound.play();
123 }
124 }
125 Key::D => mode = Mode::SetDevice,
126 Key::S => {
127 input_buf = desired_sample_rate.to_string();
128 mode = Mode::SetSampleRate;
129 }
130 Key::C => {
131 input_buf = desired_channel_count.to_string();
132 mode = Mode::SetChannelCount;
133 }
134 Key::E => {
135 input_buf = "export.wav".to_string();
136 mode = Mode::Export;
137 }
138 _ => {}
139 },
140 Mode::SetDevice => match code {
141 Key::Up => {
142 selected_dev_idx -= selected_dev_idx.saturating_sub(1);
143 }
144 Key::Down => {
145 if selected_dev_idx + 1 < devices.len() {
146 selected_dev_idx += 1;
147 }
148 }
149 Key::Enter | Key::Escape => {
150 mode = Mode::Main;
151 }
152 _ => {}
153 },
154 Mode::SetSampleRate => {
155 if code == Key::Enter {
156 desired_sample_rate = input_buf.parse()?;
157 mode = Mode::Main;
158 }
159 }
160 Mode::SetChannelCount => {
161 if code == Key::Enter {
162 desired_channel_count = input_buf.parse()?;
163 mode = Mode::Main;
164 }
165 }
166 Mode::Export => {
167 if code == Key::Enter {
168 snd_buf.save_to_file(&input_buf)?;
169 mode = Mode::Main;
170 }
171 }
172 },
173 Event::TextEntered { unicode } => match mode {
174 Mode::SetSampleRate | Mode::SetChannelCount => {
175 if unicode.is_ascii_digit() {
176 input_buf.push(unicode);
177 } else if unicode == 0x8 as char {
178 input_buf.pop();
179 }
180 }
181 Mode::Export => {
182 if !unicode.is_ascii_control() {
183 input_buf.push(unicode);
184 } else if unicode == 0x8 as char {
185 input_buf.pop();
186 }
187 }
188 Mode::Main | Mode::SetDevice => {}
189 },
190 _ => {}
191 }
192 }
193 if let Ok(samples) = recv.try_recv() {
194 samp_accum.extend_from_slice(&samples);
195 samp_buf = samples;
196 }
197 rw.clear(Color::rgb(10, 60, 40));
198 let mut writer = TextWriter::new(&font, 20, 0.0, 0.0);
199 macro_rules! w {
200 ($($arg:tt)*) => {
201 writer.write(&format!($($arg)*), &mut rw);
202 }
203 }
204 match mode {
205 Mode::Main => {
206 w!("D - set device, S - set sample rate, C - set channel count, E - export");
207 let s = if started {
208 "Press R to stop recording"
209 } else {
210 "Press R to start recording. Press P to play the recording."
211 };
212 w!("{s}");
213 w!(
214 "{} @ {} Hz\n{} samples, {} channels, {} bytes recorded",
215 driver.device(),
216 driver.sample_rate(),
217 samp_buf.len(),
218 driver.channel_count(),
219 samp_accum.len() * 2,
220 );
221 let mut rect = RectangleShape::new();
222 for (i, &sample) in samp_buf.iter().enumerate() {
223 let ratio = samp_buf.len() as f32 / rw.size().x as f32;
224 rect.set_position((i as f32 / ratio, 300.0));
225 rect.set_size((2.0, sample as f32 / 48.0));
226 rw.draw(&rect);
227 }
228 }
229 Mode::SetDevice => {
230 for (i, dev) in devices.iter().enumerate() {
231 let default_str = if dev == &*default_device {
232 " (default)"
233 } else {
234 ""
235 };
236 let color = if selected_dev_idx == i {
237 Color::YELLOW
238 } else {
239 Color::WHITE
240 };
241 writer.text.set_fill_color(color);
242 w!("{}: {}{default_str}", i + 1, dev.to_str()?);
243 }
244 }
245 Mode::SetSampleRate => {
246 w!("Enter desired sample rate");
247 w!("{input_buf}");
248 }
249 Mode::SetChannelCount => {
250 w!("Enter desired channel count");
251 w!("{input_buf}");
252 }
253 Mode::Export => {
254 w!("Enter filename to export as");
255 w!("{input_buf}");
256 }
257 }
258 rw.display();
259 }
260 Ok(())
261}
examples/cursor.rs (line 282)
72fn main() -> SfResult<()> {
73 example_ensure_right_working_dir();
74
75 let mut cursor = Cursor::from_system(CursorType::Arrow)?;
76 let mut rw = RenderWindow::new(
77 (800, 800),
78 "SFML cursor example",
79 Style::CLOSE,
80 &ContextSettings::default(),
81 )?;
82 rw.set_vertical_sync_enabled(true);
83 let font = Font::from_file("sansation.ttf")?;
84 let mut failed_index = usize::MAX;
85 let mut selected_index = usize::MAX;
86 let set_button = Rect::new(348, 500, 100, 32);
87 let hotspot_button = Rect::new(458, 500, 100, 32);
88 let clear_button = Rect::new(568, 500, 100, 32);
89 let mut pixel_grid = [false; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize];
90 let mut hotspot_selection = false;
91 let mut hotspot_selected = false;
92 let mut hotspot = Vector2::new(8, 8);
93 let mut modif = false;
94
95 let mut buttons = Vec::new();
96 let cursor_types = [
97 CursorType::Arrow,
98 CursorType::ArrowWait,
99 CursorType::Wait,
100 CursorType::Text,
101 CursorType::Hand,
102 CursorType::SizeHorizontal,
103 CursorType::SizeVertical,
104 CursorType::SizeTopLeftBottomRight,
105 CursorType::SizeBottomLeftTopRight,
106 CursorType::SizeLeft,
107 CursorType::SizeRight,
108 CursorType::SizeTop,
109 CursorType::SizeBottom,
110 CursorType::SizeTopLeft,
111 CursorType::SizeBottomRight,
112 CursorType::SizeBottomLeft,
113 CursorType::SizeTopRight,
114 CursorType::SizeAll,
115 CursorType::Cross,
116 CursorType::Help,
117 CursorType::NotAllowed,
118 ];
119 for i in 0..cursor_types.len() {
120 buttons.push(Rect::new(16, 16 + i as i32 * 36, 250, 32));
121 }
122
123 while rw.is_open() {
124 while let Some(ev) = rw.poll_event() {
125 match ev {
126 Event::Closed => rw.close(),
127 Event::MouseButtonPressed {
128 button: mouse::Button::Left,
129 x,
130 y,
131 } => {
132 for (i, b) in buttons.iter().enumerate() {
133 if mouse_over(b, x, y) {
134 match cursor.load_from_system(cursor_types[i]) {
135 Ok(()) => {
136 unsafe {
137 rw.set_mouse_cursor(&cursor);
138 }
139 selected_index = i;
140 }
141 Err(e) => {
142 eprintln!("{e}");
143 failed_index = i;
144 }
145 }
146 }
147 }
148 if mouse_over(&set_button, x, y) {
149 let mut pixels = [0; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize * 4];
150 for (i, px) in pixel_grid.iter().enumerate() {
151 let offset = i * 4;
152 if *px {
153 pixels[offset] = 255;
154 pixels[offset + 1] = 255;
155 pixels[offset + 2] = 255;
156 pixels[offset + 3] = 255;
157 }
158 }
159 unsafe {
160 match cursor.load_from_pixels(
161 &pixels,
162 Vector2::new(DRAW_GRID_WH as u32, DRAW_GRID_WH as u32),
163 hotspot,
164 ) {
165 Ok(()) => {
166 rw.set_mouse_cursor(&cursor);
167 }
168 Err(e) => {
169 eprintln!("{e}");
170 }
171 }
172 }
173 modif = false;
174 }
175 if mouse_over(&clear_button, x, y) {
176 for px in pixel_grid.iter_mut() {
177 *px = false;
178 }
179 modif = true;
180 }
181 if mouse_over(&hotspot_button, x, y) {
182 hotspot_selection = true;
183 }
184 }
185 Event::MouseButtonReleased {
186 button: mouse::Button::Left,
187 ..
188 } => {
189 if hotspot_selected {
190 hotspot_selection = false;
191 hotspot_selected = false;
192 }
193 }
194 _ => {}
195 }
196 }
197 let mut set_button_highlighted = false;
198 let mut hotspot_button_highlighted = false;
199 let mut clear_button_highlighted = false;
200 // System cursor set button interactions
201 let mp = rw.mouse_position();
202 let mut highlight_index = usize::MAX;
203 for (i, b) in buttons.iter().enumerate() {
204 if mouse_over(b, mp.x, mp.y) {
205 highlight_index = i;
206 }
207 }
208 if mouse_over(&set_button, mp.x, mp.y) {
209 set_button_highlighted = true;
210 }
211 if mouse_over(&hotspot_button, mp.x, mp.y) {
212 hotspot_button_highlighted = true;
213 }
214 if mouse_over(&clear_button, mp.x, mp.y) {
215 clear_button_highlighted = true;
216 }
217 // Grid interactions
218 let rela_x = mp.x - DRAW_AREA_TOPLEFT.0 as i32;
219 let rela_y = mp.y - DRAW_AREA_TOPLEFT.1 as i32;
220 let (gx, gy) = (rela_x / DRAW_CELL_WH as i32, rela_y / DRAW_CELL_WH as i32);
221 if gx >= 0 && gy >= 0 {
222 if let Some(cell) = gridindex(&mut pixel_grid, gx as usize, gy as usize) {
223 if hotspot_selection {
224 hotspot_selected = true;
225 hotspot = Vector2::new(gx as u32, gy as u32);
226 modif = true;
227 } else if mouse::Button::Left.is_pressed() {
228 *cell = true;
229 modif = true;
230 } else if mouse::Button::Right.is_pressed() {
231 *cell = false;
232 modif = true;
233 }
234 }
235 }
236 rw.clear(Color::BLACK);
237 // Draw system cursor set buttons
238 let mut shape = RectangleShape::default();
239 let mut text = Text::new("", &font, 14);
240 shape.set_outline_thickness(-1.0);
241 shape.set_outline_color(Color::WHITE);
242 for (i, b) in buttons.iter().enumerate() {
243 let types = [
244 "ARROW",
245 "ARROW_WAIT",
246 "WAIT",
247 "TEXT",
248 "HAND",
249 "SIZE_HORIZONTAL",
250 "SIZE_VERTICAL",
251 "SIZE_TOP_LEFT_BOTTOM_RIGHT",
252 "SIZE_BOTTOM_LEFT_TOP_RIGHT",
253 "SIZE_LEFT",
254 "SIZE_RIGHT",
255 "SIZE_TOP",
256 "SIZE_BOTTOM",
257 "SIZE_TOP_LEFT",
258 "SIZE_BOTTOM_RIGHT",
259 "SIZE_BOTTOM_LEFT",
260 "SIZE_TOP_RIGHT",
261 "SIZE_ALL",
262 "CROSS",
263 "HELP",
264 "NOT_ALLOWED",
265 ];
266 draw_button(
267 b,
268 &mut shape,
269 &mut text,
270 types[i],
271 &mut rw,
272 bstyle(highlight_index == i, selected_index == i, failed_index == i),
273 );
274 }
275 // Draw pixel drawing grid
276 shape.set_fill_color(Color::TRANSPARENT);
277 for y in 0..DRAW_GRID_WH {
278 for x in 0..DRAW_GRID_WH {
279 if hotspot.x == x as u32 && hotspot.y == y as u32 {
280 shape.set_outline_color(Color::RED);
281 } else {
282 shape.set_outline_color(Color::rgb(180, 180, 180));
283 }
284 if gridindex(&mut pixel_grid, x as usize, y as usize).is_some_and(|bool| *bool) {
285 shape.set_fill_color(Color::WHITE);
286 } else {
287 shape.set_fill_color(Color::TRANSPARENT);
288 }
289 shape.set_size((DRAW_CELL_WH as f32, DRAW_CELL_WH as f32));
290 shape.set_position((
291 DRAW_AREA_TOPLEFT.0 as f32 + (x as f32 * DRAW_CELL_WH as f32),
292 DRAW_AREA_TOPLEFT.1 as f32 + (y as f32 * DRAW_CELL_WH as f32),
293 ));
294 rw.draw(&shape);
295 }
296 }
297 draw_button(
298 &set_button,
299 &mut shape,
300 &mut text,
301 if modif { "Set*" } else { "Set" },
302 &mut rw,
303 bstyle(set_button_highlighted, false, false),
304 );
305 draw_button(
306 &hotspot_button,
307 &mut shape,
308 &mut text,
309 "Hotspot",
310 &mut rw,
311 bstyle(hotspot_button_highlighted, hotspot_selection, false),
312 );
313 draw_button(
314 &clear_button,
315 &mut shape,
316 &mut text,
317 "Clear",
318 &mut rw,
319 bstyle(clear_button_highlighted, false, false),
320 );
321 rw.display();
322 }
323 Ok(())
324}
examples/pong.rs (line 68)
21fn main() -> SfResult<()> {
22 example_ensure_right_working_dir();
23
24 let mut rng = thread_rng();
25
26 // Optional antialiasing
27 let mut aa_level = 0;
28
29 if let Some(arg) = env::args().nth(1) {
30 match arg.parse::<u32>() {
31 Ok(arg_as_num) => aa_level = arg_as_num,
32 Err(e) => println!("Didn't set AA level: {e}"),
33 }
34 }
35
36 // Define some constants
37 let game_width = 800;
38 let game_height = 600;
39 let paddle_size = Vector2f::new(25., 100.);
40 let ball_radius = 10.;
41
42 // Create the window of the application
43 let context_settings = ContextSettings {
44 antialiasing_level: aa_level,
45 ..Default::default()
46 };
47 let mut window = RenderWindow::new(
48 (game_width, game_height),
49 "SFML Pong",
50 Style::CLOSE,
51 &context_settings,
52 )?;
53 let context_settings = window.settings();
54 if context_settings.antialiasing_level > 0 {
55 println!("Using {}xAA", context_settings.antialiasing_level);
56 }
57 window.set_vertical_sync_enabled(true);
58
59 // Load the sounds used in the game
60 let ball_soundbuffer = SoundBuffer::from_file("ball.wav")?;
61 let mut ball_sound = Sound::with_buffer(&ball_soundbuffer);
62
63 // Create the left paddle
64 let mut left_paddle = RectangleShape::new();
65 left_paddle.set_size(paddle_size - Vector2f::new(3., 3.));
66 left_paddle.set_outline_thickness(3.);
67 left_paddle.set_outline_color(Color::BLACK);
68 left_paddle.set_fill_color(Color::rgb(100, 100, 200));
69 left_paddle.set_origin(paddle_size / 2.);
70
71 // Create the right paddle
72 let mut right_paddle = RectangleShape::new();
73 right_paddle.set_size(paddle_size - Vector2f::new(3., 3.));
74 right_paddle.set_outline_thickness(3.);
75 right_paddle.set_outline_color(Color::BLACK);
76 right_paddle.set_fill_color(Color::rgb(200, 100, 100));
77 right_paddle.set_origin(paddle_size / 2.);
78
79 // Create the ball
80 let mut ball = CircleShape::default();
81 ball.set_radius(ball_radius - 3.);
82 ball.set_outline_thickness(3.);
83 ball.set_outline_color(Color::BLACK);
84 ball.set_fill_color(Color::WHITE);
85 ball.set_origin(ball_radius / 2.);
86
87 // Load the text font
88 let font = Font::from_file("sansation.ttf")?;
89
90 // Initialize the pause message
91 let mut pause_message = Text::default();
92 pause_message.set_font(&font);
93 pause_message.set_character_size(40);
94 pause_message.set_position((170., 150.));
95 pause_message.set_fill_color(Color::WHITE);
96 pause_message.set_string("Welcome to SFML pong!\nPress space to start the game");
97
98 // Define the paddles properties
99 let mut ai_timer = Clock::start()?;
100 let paddle_speed = 400.;
101 let mut right_paddle_speed = 0.;
102 let mut ball_speed = 400.;
103 let mut ball_angle = 0.;
104
105 let mut clock = Clock::start()?;
106 let mut is_playing = false;
107 let mut up = false;
108 let mut down = false;
109
110 'mainloop: loop {
111 while let Some(event) = window.poll_event() {
112 match event {
113 Event::Closed
114 | Event::KeyPressed {
115 code: Key::Escape, ..
116 } => break 'mainloop,
117 Event::KeyPressed {
118 code: Key::Space, ..
119 } if !is_playing => {
120 // (re)start the game
121 is_playing = true;
122 ball_speed = 400.0;
123 ball_sound.set_pitch(1.0);
124 clock.restart();
125 // Reset the position of the paddles and ball
126 left_paddle.set_position((10. + paddle_size.x / 2., game_height as f32 / 2.));
127 right_paddle.set_position((
128 game_width as f32 - 10. - paddle_size.x / 2.,
129 game_height as f32 / 2.,
130 ));
131 ball.set_position((game_width as f32 / 2., game_height as f32 / 2.));
132 // Reset the ball angle
133 loop {
134 // Make sure the ball initial angle is not too much vertical
135 ball_angle = rng.gen_range(0.0..360.) * 2. * PI / 360.;
136
137 if ball_angle.cos().abs() >= 0.7 {
138 break;
139 }
140 }
141 }
142 Event::KeyPressed { code: Key::Up, .. }
143 | Event::KeyPressed {
144 scan: Scancode::W, ..
145 } => up = true,
146 Event::KeyReleased { code: Key::Up, .. }
147 | Event::KeyReleased {
148 scan: Scancode::W, ..
149 } => up = false,
150 Event::KeyPressed {
151 code: Key::Down, ..
152 }
153 | Event::KeyPressed {
154 scan: Scancode::S, ..
155 } => down = true,
156 Event::KeyReleased {
157 code: Key::Down, ..
158 }
159 | Event::KeyReleased {
160 scan: Scancode::S, ..
161 } => down = false,
162 _ => {}
163 }
164 }
165 if is_playing {
166 let delta_time = clock.restart().as_seconds();
167
168 // Move the player's paddle
169 if up && (left_paddle.position().y - paddle_size.y / 2. > 5.) {
170 left_paddle.move_((0., -paddle_speed * delta_time));
171 }
172 if down && (left_paddle.position().y + paddle_size.y / 2. < game_height as f32 - 5.) {
173 left_paddle.move_((0., paddle_speed * delta_time));
174 }
175
176 // Move the computer's paddle
177 if ((right_paddle_speed < 0.) && (right_paddle.position().y - paddle_size.y / 2. > 5.))
178 || ((right_paddle_speed > 0.)
179 && (right_paddle.position().y + paddle_size.y / 2. < game_height as f32 - 5.))
180 {
181 right_paddle.move_((0., right_paddle_speed * delta_time));
182 }
183
184 // Update the computer's paddle direction according to the ball position
185 if ai_timer.elapsed_time() > AI_REACT_DELAY {
186 ai_timer.restart();
187 if ball.position().y + ball_radius > right_paddle.position().y + paddle_size.y / 2.
188 {
189 right_paddle_speed = paddle_speed;
190 } else if ball.position().y - ball_radius
191 < right_paddle.position().y - paddle_size.y / 2.
192 {
193 right_paddle_speed = -paddle_speed;
194 } else {
195 right_paddle_speed = 0.;
196 }
197 }
198
199 // Move the ball
200 let factor = ball_speed * delta_time;
201 ball.move_((ball_angle.cos() * factor, ball_angle.sin() * factor));
202
203 // Check collisions between the ball and the screen
204 if ball.position().x - ball_radius < 0. {
205 is_playing = false;
206 pause_message.set_string("You lost !\nPress space to restart or\nescape to exit");
207 }
208 if ball.position().x + ball_radius > game_width as f32 {
209 is_playing = false;
210 pause_message.set_string("You won !\nPress space to restart or\nescape to exit");
211 }
212 if ball.position().y - ball_radius < 0. {
213 on_bounce(&mut ball_sound, &mut ball_speed);
214 ball_angle = -ball_angle;
215 let p = ball.position().x;
216 ball.set_position((p, ball_radius + 0.1));
217 }
218 if ball.position().y + ball_radius > game_height as f32 {
219 on_bounce(&mut ball_sound, &mut ball_speed);
220 ball_angle = -ball_angle;
221 let p = ball.position().x;
222 ball.set_position((p, game_height as f32 - ball_radius - 0.1));
223 }
224
225 // Check the collisions between the ball and the paddles
226 // Left Paddle
227 let (ball_pos, paddle_pos) = (ball.position(), left_paddle.position());
228 if ball_pos.x - ball_radius < paddle_pos.x + paddle_size.x / 2.
229 && ball_pos.y + ball_radius >= paddle_pos.y - paddle_size.y / 2.
230 && ball_pos.y - ball_radius <= paddle_pos.y + paddle_size.y / 2.
231 {
232 if ball_pos.y > paddle_pos.y {
233 ball_angle = PI - ball_angle + rng.gen_range(0.0..20.) * PI / 180.;
234 } else {
235 ball_angle = PI - ball_angle - rng.gen_range(0.0..20.) * PI / 180.;
236 }
237
238 on_bounce(&mut ball_sound, &mut ball_speed);
239 ball.set_position((
240 paddle_pos.x + ball_radius + paddle_size.x / 2. + 0.1,
241 ball_pos.y,
242 ));
243 }
244
245 // Right Paddle
246 let (ball_pos, paddle_pos) = (ball.position(), right_paddle.position());
247 if ball_pos.x + ball_radius > paddle_pos.x - paddle_size.x / 2.
248 && ball_pos.y + ball_radius >= paddle_pos.y - paddle_size.y / 2.
249 && ball_pos.y - ball_radius <= paddle_pos.y + paddle_size.y / 2.
250 {
251 if ball_pos.y > paddle_pos.y {
252 ball_angle = PI - ball_angle + rng.gen_range(0.0..20.) * PI / 180.;
253 } else {
254 ball_angle = PI - ball_angle - rng.gen_range(0.0..20.) * PI / 180.;
255 }
256
257 on_bounce(&mut ball_sound, &mut ball_speed);
258 ball.set_position((
259 paddle_pos.x - ball_radius - paddle_size.x / 2. - 0.1,
260 ball_pos.y,
261 ));
262 }
263 }
264 // Clear the window
265 window.clear(Color::rgb(50, 200, 50));
266
267 if is_playing {
268 // Draw the paddles and the ball
269 window.draw(&left_paddle);
270 window.draw(&right_paddle);
271 window.draw(&ball);
272 } else {
273 // Draw the pause message
274 window.draw(&pause_message);
275 }
276
277 // Display things on screen
278 window.display()
279 }
280 Ok(())
281}
Sourcepub const fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self
pub const fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self
Construct a color from its 4 RGBA components
§Arguments
- red - Red component (0 .. 255)
- green - -Green component (0 .. 255)
- blue - Blue component (0 .. 255)
- alpha - Alpha component (0 .. 255)
Return Color object constructed from the components
Examples found in repository?
examples/shader.rs (line 284)
258fn main() -> SfResult<()> {
259 example_ensure_right_working_dir();
260
261 let mut window = RenderWindow::new(
262 (800, 600),
263 "SFML Shader",
264 Style::TITLEBAR | Style::CLOSE,
265 &Default::default(),
266 )?;
267 window.set_vertical_sync_enabled(true);
268 let font = Font::from_file("sansation.ttf")?;
269 let bg = Texture::from_file("background.jpg")?;
270 let mut bg_texture = Texture::from_file("sfml.png")?;
271 bg_texture.set_smooth(true);
272 let mut entity_texture = Texture::from_file("devices.png")?;
273 entity_texture.set_smooth(true);
274 let effects: [&mut dyn Effect; 4] = [
275 &mut Pixelate::new(&bg)?,
276 &mut WaveBlur::new(&font)?,
277 &mut StormBlink::new()?,
278 &mut Edge::new(&bg_texture, &entity_texture)?,
279 ];
280 let mut current = 0;
281 let text_bg_texture = Texture::from_file("text-background.png")?;
282 let mut text_bg = Sprite::with_texture(&text_bg_texture);
283 text_bg.set_position((0., 520.));
284 text_bg.set_color(Color::rgba(255, 255, 255, 200));
285 let msg = format!("Current effect: {}", effects[current].name());
286 let mut desc = Text::new(&msg, &font, 20);
287 desc.set_position((10., 530.));
288 desc.set_fill_color(Color::rgb(80, 80, 80));
289 let msg = "Press left and right arrows to change the current shader";
290 let mut instructions = Text::new(msg, &font, 20);
291 instructions.set_position((280., 555.));
292 instructions.set_fill_color(Color::rgb(80, 80, 80));
293 let clock = Clock::start()?;
294
295 while window.is_open() {
296 while let Some(event) = window.poll_event() {
297 use crate::Event::*;
298 match event {
299 Closed => window.close(),
300 KeyPressed { code, .. } => match code {
301 Key::Escape => window.close(),
302 Key::Left => {
303 if current == 0 {
304 current = effects.len() - 1;
305 } else {
306 current -= 1;
307 }
308 desc.set_string(&format!("Current effect: {}", effects[current].name()));
309 }
310 Key::Right => {
311 if current == effects.len() - 1 {
312 current = 0;
313 } else {
314 current += 1;
315 }
316 desc.set_string(&format!("Current effect: {}", effects[current].name()));
317 }
318 _ => {}
319 },
320 _ => {}
321 }
322 }
323
324 let x = window.mouse_position().x as f32 / window.size().x as f32;
325 let y = window.mouse_position().y as f32 / window.size().y as f32;
326
327 effects[current].update(clock.elapsed_time().as_seconds(), x, y)?;
328
329 window.clear(Color::rgb(255, 128, 0));
330 window.draw(effects[current].as_drawable());
331 window.draw(&text_bg);
332 window.draw(&instructions);
333 window.draw(&desc);
334 window.display();
335 }
336 Ok(())
337}
More examples
examples/opengl.rs (line 46)
16fn main() -> SfResult<()> {
17 example_ensure_right_working_dir();
18
19 let mut exit = false;
20 let mut srgb = false;
21
22 while !exit {
23 let ctx_sett = ContextSettings {
24 depth_bits: 24,
25 srgb_capable: srgb,
26 ..Default::default()
27 };
28
29 let mut window = RenderWindow::new(
30 (800, 600),
31 "SFML graphics with OpenGL",
32 Style::default(),
33 &ctx_sett,
34 )?;
35 window.set_vertical_sync_enabled(true);
36
37 let mut bg_tex = Texture::new()?;
38 bg_tex.set_srgb(srgb);
39 bg_tex.load_from_file("opengl-background.jpg", IntRect::default())?;
40 let bg_sprite = Sprite::with_texture(&bg_tex);
41
42 let font = Font::from_file("sansation.ttf")?;
43 let mut text = Text::new("SFML / OpenGL demo", &font, 32);
44 let mut srgb_instr = Text::new("Press space to toggle sRGB conversion", &font, 32);
45 let mut mipmap_instr = Text::new("Press return to toggle mipmapping", &font, 32);
46 text.set_fill_color(Color::rgba(255, 255, 255, 170));
47 srgb_instr.set_fill_color(Color::rgba(255, 255, 255, 170));
48 mipmap_instr.set_fill_color(Color::rgba(255, 255, 255, 170));
49 text.set_position((250., 450.));
50 srgb_instr.set_position((150., 500.));
51 mipmap_instr.set_position((180., 550.));
52
53 let mut texture = Texture::from_file("texture.jpg")?;
54 texture.generate_mipmap()?;
55 window.set_active(true)?;
56 unsafe {
57 gl::glEnable(gl::GL_DEPTH_TEST);
58 gl::glDepthMask(gl::GL_TRUE as _);
59 gl::glClearDepth(1.);
60 gl::glDisable(gl::GL_LIGHTING);
61 gl::glViewport(0, 0, window.size().x as _, window.size().y as _);
62 gl::glMatrixMode(gl::GL_PROJECTION);
63 gl::glLoadIdentity();
64 let ratio = (window.size().x / window.size().y) as gl::GLdouble;
65 gl::glFrustum(-ratio, ratio, -1., 1., 1., 500.);
66 gl::glEnable(gl::GL_TEXTURE_2D);
67 Texture::bind(&texture);
68 }
69
70 let cube: [f32; 180] = [
71 -20., -20., -20., 0., 0., -20., 20., -20., 1., 0., -20., -20., 20., 0., 1., -20., -20.,
72 20., 0., 1., -20., 20., -20., 1., 0., -20., 20., 20., 1., 1., 20., -20., -20., 0., 0.,
73 20., 20., -20., 1., 0., 20., -20., 20., 0., 1., 20., -20., 20., 0., 1., 20., 20., -20.,
74 1., 0., 20., 20., 20., 1., 1., -20., -20., -20., 0., 0., 20., -20., -20., 1., 0., -20.,
75 -20., 20., 0., 1., -20., -20., 20., 0., 1., 20., -20., -20., 1., 0., 20., -20., 20.,
76 1., 1., -20., 20., -20., 0., 0., 20., 20., -20., 1., 0., -20., 20., 20., 0., 1., -20.,
77 20., 20., 0., 1., 20., 20., -20., 1., 0., 20., 20., 20., 1., 1., -20., -20., -20., 0.,
78 0., 20., -20., -20., 1., 0., -20., 20., -20., 0., 1., -20., 20., -20., 0., 1., 20.,
79 -20., -20., 1., 0., 20., 20., -20., 1., 1., -20., -20., 20., 0., 0., 20., -20., 20.,
80 1., 0., -20., 20., 20., 0., 1., -20., 20., 20., 0., 1., 20., -20., 20., 1., 0., 20.,
81 20., 20., 1., 1.,
82 ];
83
84 unsafe {
85 gl::glEnableClientState(gl::GL_VERTEX_ARRAY);
86 gl::glEnableClientState(gl::GL_TEXTURE_COORD_ARRAY);
87 gl::glVertexPointer(
88 3,
89 gl::GL_FLOAT,
90 5 * size_of::<gl::GLfloat>() as i32,
91 cube.as_ptr() as *const c_void,
92 );
93 gl::glTexCoordPointer(
94 2,
95 gl::GL_FLOAT,
96 5 * size_of::<gl::GLfloat>() as i32,
97 cube.as_ptr().offset(3) as *const c_void,
98 );
99
100 // Disable normal and color vertex components
101 gl::glDisableClientState(gl::GL_NORMAL_ARRAY);
102 gl::glDisableClientState(gl::GL_COLOR_ARRAY);
103 }
104
105 window.set_active(false)?;
106 let clock = Clock::start()?;
107 let mut mipmap_enabled = true;
108
109 while window.is_open() {
110 while let Some(event) = window.poll_event() {
111 match event {
112 Event::Closed
113 | Event::KeyPressed {
114 code: Key::Escape, ..
115 } => {
116 exit = true;
117 window.close();
118 }
119 Event::KeyPressed {
120 code: Key::Enter, ..
121 } => {
122 if mipmap_enabled {
123 texture = Texture::from_file("texture.jpg")?;
124 mipmap_enabled = false;
125 window.set_active(true)?;
126 Texture::bind(&texture);
127 window.set_active(false)?;
128 } else {
129 texture.generate_mipmap()?;
130 mipmap_enabled = true;
131 }
132 }
133 Event::KeyPressed {
134 code: Key::Space, ..
135 } => {
136 srgb = !srgb;
137 window.close();
138 }
139 Event::Resized { width, height } => {
140 window.set_active(true)?;
141 unsafe {
142 gl::glViewport(0, 0, width as _, height as _);
143 }
144 window.set_active(false)?;
145 }
146 _ => {}
147 }
148 }
149 window.push_gl_states();
150 window.draw(&bg_sprite);
151 window.pop_gl_states();
152
153 if let Err(e) = window.set_active(true) {
154 eprintln!("Failed to set window as active: {e}");
155 }
156
157 unsafe {
158 gl::glClear(gl::GL_DEPTH_BUFFER_BIT);
159 let x: f32 =
160 window.mouse_position().x as f32 * 200. / window.size().x as f32 - 100.;
161 let y: f32 =
162 -window.mouse_position().y as f32 * 200. / window.size().y as f32 + 100.;
163
164 gl::glMatrixMode(gl::GL_MODELVIEW);
165 gl::glLoadIdentity();
166 gl::glTranslatef(x, y, -100.);
167 gl::glRotatef(clock.elapsed_time().as_seconds() * 50., 1., 0., 0.);
168 gl::glRotatef(clock.elapsed_time().as_seconds() * 30., 0., 1., 0.);
169 gl::glRotatef(clock.elapsed_time().as_seconds() * 90., 0., 0., 1.);
170 gl::glDrawArrays(gl::GL_TRIANGLES, 0, 36);
171 }
172 if let Err(e) = window.set_active(false) {
173 eprintln!("Failed to set window as active: {e}");
174 }
175 window.push_gl_states();
176 window.draw(&text);
177 window.draw(&srgb_instr);
178 window.draw(&mipmap_instr);
179 window.pop_gl_states();
180 window.display();
181 }
182 }
183 Ok(())
184}
Trait Implementations§
Source§impl AddAssign for Color
impl AddAssign for Color
Source§fn add_assign(&mut self, rhs: Self)
fn add_assign(&mut self, rhs: Self)
Performs the
+=
operation. Read moreSource§impl MulAssign for Color
impl MulAssign for Color
Source§fn mul_assign(&mut self, rhs: Self)
fn mul_assign(&mut self, rhs: Self)
Performs the
*=
operation. Read moreSource§impl SubAssign for Color
impl SubAssign for Color
Source§fn sub_assign(&mut self, rhs: Self)
fn sub_assign(&mut self, rhs: Self)
Performs the
-=
operation. Read moreimpl Copy for Color
impl Eq for Color
impl StructuralPartialEq for Color
Auto Trait Implementations§
impl Freeze for Color
impl RefUnwindSafe for Color
impl Send for Color
impl Sync for Color
impl Unpin for Color
impl UnwindSafe for Color
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more