Giter VIP home page Giter VIP logo

oort3's Introduction

Oort

A space fleet programming game. Hosted at http://oort.rs.

Development

Prerequisites: cargo install trunk wasm-opt

Run "cargo oort-serve" to start a webserver at http://localhost:8080/. The first run will take several minutes to build everything.

Copyright

Copyright 2023 Rich Lane. Licensed under GPLv3, see LICENSE.

oort3's People

Contributors

0e4ef622 avatar ava5627 avatar dependabot[bot] avatar derivator avatar easyoakland avatar jhuang97 avatar mwlsk avatar nudelmeister avatar rlane avatar scarf005 avatar szabgab avatar twof avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

oort3's Issues

Possibility to replace db

Hello, I just discovered this project and find it great. I just wonder how hard it would be to replace firebase by a simple sqlite (or other) for the database, especially to self host the project ?

Acceleration seems incorrect?

If you run the acceleration tutorial (2), with the code:

// Tutorial: Acceleration
// Fly through the target circle.
use oort_api::prelude::*;

pub struct Ship {
    saved_vel: Vec2,
}

impl Ship {
    pub fn new() -> Ship {
        Ship {
            saved_vel: vec2(0.0, 0.0),
        }
    }

    pub fn tick(&mut self) {
        debug!("Velocity: {}", self.saved_vel);

        if (current_tick() == 60) {
            self.saved_vel = velocity();
        }

        accelerate(vec2(100.0, 0.0));
    }
}

Then you will get
Velocity: [60, 0]
But this seems incorrect if you are applying an acceleration of 100 mpss if 60 ticks are a second.
Shouldn't it be 100 mpss at 60 ticks instead of 60 mpss?

turn(0.0) does not stop turning

if i use turn(0.0) to stop the rotation, it will oscillate between -0.00000000000000005551115123125783 and 0.1047197551196597

0.104 is significant error, as it is 6deg/s of rotation

use oort_api::prelude::*;

pub struct Ship {}

impl Ship {
    pub fn new() -> Ship {
        Ship {}
    }

    pub fn tick(&mut self) {
        debug!("tick: {0}", current_tick());
        let angular_velocity = angular_velocity();
        debug!("angular_velocity: {angular_velocity}");
        if current_tick() < 10{
            torque(1000.0);
            return;
        }
        debug!("BREAKING");
        turn(0.0); //this should stop us!
    }
}

Error on compiling repo

error[E0433]: failed to resolve: use of undeclared crate or module wasmer_compiler_singlepass
--> shared/simulator/src/vm/mod.rs:261:36
|
261 | let mut store = Store::new(wasmer_compiler_singlepass::Singlepass::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared crate or module wasmer_compiler_singlepass

For more information about this error, try rustc --explain E0433.
error: could not compile oort_simulator (lib) due to previous error

Compiler: Unknown Language

I have been coding in an external editor, using a rust bundler. After making some changes to my code and increasing it's length, the compiler refuses to compile and just says "Unknown Language." I've verified that the right code is being input, so I'm not sure what the issue is.

Here is my bundled source (exactly as the compiler receives it)

pub mod oort_ai_v2 {
use oort_api::prelude::*;
#[cfg(test)]
pub mod test {
use oort_api::prelude::*;
use byteorder::{ByteOrder, ReadBytesExt, BE, LE};
use std::io::{Cursor, Read};
use super::api::comms::*;
#[test]
fn test_serde_vec4() {
let vec = vec2(16.0 * 500.0, 16.0 * 811.0);
let bytes = serialize_vec_i16(vec);
println!("bytes: {:0>8b} {:0>8b}, {:0>8b} {:0>8b}", bytes[0], bytes[1], bytes[2], bytes[3]);
let new_vec = deserialize_vec_i16(&bytes);
assert_eq!(vec, new_vec, "Data preserved by serde_vec4");
}
#[test]
fn test_serde_vec8() {
let vec = vec2(500.0, 811.0);
let bytes = serialize_vec_f32(vec);
let new_vec = deserialize_vec_f32(&bytes);
assert_eq!(vec, new_vec, "Data preserved by serde_vec8");
}
}
pub mod api {
pub mod comms {
use std::io::Cursor;
use oort_api::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, ByteOrder, BE};
pub fn serialize_vec_i16(vec: Vec2) -> [u8; 4]{
let x = vec.x.round_ties_even() as i16;
let y = vec.y.round_ties_even() as i16;
[
(y >> 8) as u8,
y as u8,
(x >> 8) as u8,
x as u8,
]
}
pub fn deserialize_vec_i16(data: &[u8; 4]) -> Vec2{
vec2(
((data[2] as i16) << 8 | (data[3] as i16)) as f64,
((data[0] as i16) << 8 | (data[1] as i16)) as f64,
)
}
pub fn serialize_vec_f32(vec: Vec2) -> [u8; 8]{
let mut writer = Cursor::new([0; 8]);
writer.write_f32::<BE>(vec.x as f32).unwrap();
writer.write_f32::<BE>(vec.y as f32).unwrap();
writer.into_inner()
}
pub fn deserialize_vec_f32(data: &[u8; 8]) -> Vec2 {
let mut reader = Cursor::new(data);
let x = reader.read_f32::<BE>().unwrap();
let y = reader.read_f32::<BE>().unwrap();
vec2(x as f64, y as f64)
}
pub enum MessageData {
EnemyArea(Vec2)
} impl MessageData {
pub fn serialize(self) {
match self {
MessageData::EnemyArea(pos) => todo!(),
}
}
}
pub struct Message {
data: MessageData,
sender: u16,
}
}
pub mod targeting {
use oort_api::prelude::*;
#[derive(Clone, Copy, PartialEq)]
pub struct Target {
pub class: Class,
pub position: Vec2,
pub velocity: Vec2,
pub last_seen: f64,
} impl From<ScanResult> for Target {
fn from(value: ScanResult) -> Self {
Target {
class: value.class,
position: value.position,
velocity: value.velocity,
last_seen: current_time(),
}
}
} impl Target {
pub fn vec_to(&self) -> Vec2 {
self.position - position()
}
pub fn angle_to(&self) -> f64 {
self.vec_to().angle()
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum RadarOperation {
Search(f64), //dist
Look(f64), //angle
Track(Target),
}
#[derive(Clone, Copy, PartialEq)]
pub struct RadarStatus {
heading: f64,
width: f64,
min: f64,
max: f64,
ecm: EcmMode,
} impl RadarStatus {
pub fn save() -> Self {
RadarStatus {
heading: radar_heading(),
width: radar_width(),
min: radar_min_distance(),
max: radar_max_distance(),
ecm: radar_ecm_mode(),
}
}
pub fn restore(self) {
set_radar_heading(self.heading);
set_radar_width(self.width);
set_radar_min_distance(self.min);
set_radar_max_distance(self.max);
set_radar_ecm_mode(self.ecm);
}
}
pub struct RadarBeamSearcher {
pub width: f64,
pub min: f64,
pub max: f64,
} impl RadarBeamSearcher {
pub fn new() -> Self {
RadarBeamSearcher {
width: TAU / 10.0,
min: 2.0,
max: 20000.0,
}
}
pub fn tick(&self) {
set_radar_heading(heading());
set_radar_min_distance(self.min);
set_radar_max_distance(self.max);
set_radar_width(self.width);
}
pub fn get_target(&self) -> Option<Target> {
scan().map(|v| v.into())
}
}
pub struct RadarBeamSweeper {
pub width: f64,
pub min: f64,
pub max: f64,
look_angle: f64,
target: Option<Target>,
} impl RadarBeamSweeper {
pub fn new() -> Self {
RadarBeamSweeper {
width: TAU / 10.0,
min: 2.0,
max: 20000.0,
look_angle: 0.0,
target: None,
}
}
pub fn tick(&mut self) {
if let Some(result) = scan() {
let result = Target::from(result);
self.target = Some(result);
self.look_angle = result.angle_to();
debug!("Sweeper: Active");
} else if let Some(target) = self.target {
let age = current_time() - target.last_seen;
debug!("Sweeper: Last-Seen {age} ago");
if age > 2.5 {
self.target.take();
}
} else {
debug!("Sweeper: Scanning");
self.look_angle += self.width / 5.0;
}
set_radar_heading(self.look_angle);
set_radar_min_distance(self.min);
set_radar_max_distance(self.max);
set_radar_width(self.width);
}
pub fn get_target(&self) -> Option<Target> {
self.target
}
}
pub struct RadarTracker {
operations: Vec<(RadarStatus, RadarOperation)>
}
}
pub mod control {
pub mod movement {
use oort_api::prelude::*;
#[allow(dead_code)]
pub fn lerp(a: f64, b: f64, d: f64) -> f64 {
(1.0 - d) * a + d * b
}
pub fn max_accel(current_heading: f64, target_heading: f64) -> f64 {
let offset = angle_diff(target_heading, current_heading+PI/2.0) + PI;
let quarter = (offset / (TAU / 4.0)) as u32;
let mut quarter_offset = offset;
while quarter_offset > TAU / 4.0 {
quarter_offset -= TAU / 4.0;
}
quarter_offset = quarter_offset * 4.0 / TAU;
match quarter {
0 => lerp(max_lateral_acceleration(), max_backward_acceleration(), quarter_offset),
1 => lerp(max_backward_acceleration(), max_lateral_acceleration(), quarter_offset),
2 => lerp(max_lateral_acceleration(), max_forward_acceleration(), quarter_offset),
3 => lerp(max_forward_acceleration(), max_lateral_acceleration(), quarter_offset),
_ => unreachable!(),
}
}
pub enum ActionControl<T> {
NoControl,
Auto,
Manual(T),
}
pub type AngleControl = ActionControl<f64>;
}
pub mod pid {
#[allow(dead_code)]
pub struct PID {
pub gain_p: f64,
pub gain_i: f64,
pub gain_d: f64,
prev_error: Option<f64>,
idle_time: u32,
} impl PID {
pub fn solve(&mut self, error: f64, dt: f64) -> f64 {
let p = error;
let i = 0.0;
let d;
if let Some(prev_error) = self.prev_error.replace(error) {
d = (error - prev_error) / dt;
self.prev_error.replace(error);
} else {
d = 0.0;
}
let out = p * self.gain_p
+ i * self.gain_i
+ d * self.gain_d;
out
}
pub fn new(gain_p: f64, gain_i: f64, gain_d: f64, output_rate: f64) -> Self {
PID {
gain_p: gain_p * output_rate,
gain_i: gain_i * output_rate,
gain_d: gain_d * output_rate,
prev_error: None,
idle_time: 0,
}
}
pub fn reset(&mut self) {
self.prev_error = None;
}
pub fn idle(&mut self) {
if self.prev_error.is_some() {
self.idle_time += 1;
if self.idle_time > 15 {
self.prev_error.take();
self.idle_time = 0;
}
}
}
}
}
pub mod point {
use oort_api::prelude::*;
use super::super::super::api::{control::{movement::max_accel, pid::PID}, targeting::Target};
#[allow(dead_code)]
pub struct PointAutopilot {
angle_pid: PID,
position_pid: PID,
auto_angle: bool,
infinite_accel: bool,
pub allow_boost: bool,
orbit_distance: f64,
target_angle: Option<f64>,
target_location: Option<Vec2>,
angle_error: Option<f64>,
} impl PointAutopilot {
pub fn new() -> Self {
PointAutopilot {
angle_pid: PID::new(1.0, 0.0, 1.0, max_angular_acceleration()),
position_pid: PID::new(0.5, 0.0, 1.5, 1.0),
auto_angle: true,
infinite_accel: false,
allow_boost: false,
orbit_distance: 0.0,
target_angle: None,
target_location: None,
angle_error: None,
}
}
pub fn tick(&mut self) {
let mut is_at_target = false;
if let Some(target) = self.target_location {
if (target - position()).length() < self.orbit_distance + 3.0 {
is_at_target = true;
}
}
debug!("Point @{} >{} ('{}')", match (self.target_location, self.infinite_accel, is_at_target) {
(Some(_), _, true) => "++",
(Some(_), false, _) => "To",
(Some(_), true, _) => "Cross",
(None, _, _) => "OVERRIDE",
}, match (self.target_angle, self.auto_angle) {
(_, true) => "Auto",
(Some(_), false) => "Specific",
(None, false) => "OVERRIDE",
}, match (self.target_location, self.infinite_accel, self.target_angle, self.auto_angle) {
(Some(location), false, None, true) => {
draw_line(position(), location, 0xFFFF00);
"goto"
},
(Some(location), true, None, true) => {
draw_line(position(), location, 0xFFFF00);
draw_diamond(location, 10.0, 0xFFFF00);
"flyby"
},
(Some(location), _, None, false) => {
draw_line(position(), location, 0xFF0000);
"strafe"
},
(Some(location), _, Some(angle), false) => {
draw_line(position(), location, 0xFF0000);
draw_line(position(), position() + vec2(100.0, 0.0).rotate(angle), 0x00FF00);
"target-strafe"
},
(None, _, Some(angle), _) => {
draw_line(position(), position() + vec2(100.0, 0.0).rotate(angle), 0x00FF00);
"point-at"
},
(None, _, None, _) => "idle",
_ => "?",
});
let mut target_angle = self.target_angle.clone();
if let Some(target) = self.target_location {
let vec_between = target - position();
if self.auto_angle {
target_angle = Some(vec_between.angle());
}
if self.orbit_distance > 0.0 {
draw_polygon(target, self.orbit_distance, 10, current_time(), 0xFF00FF);
}
if !is_at_target && fuel() > 0.0 {
if self.allow_boost {
if self.angle_error.is_some_and(|v| v.abs() < TAU/32.0) && vec_between.length() - self.orbit_distance > 100.0 {
activate_ability(Ability::Boost);
} else if self.angle_error.is_some_and(|v| v.abs() > TAU / 16.0) {
deactivate_ability(Ability::Boost);
}
}
if self.infinite_accel {
accelerate(vec_between.normalize() * max_forward_acceleration());
} else {
let impulse = self.position_pid.solve(vec_between.length() - self.orbit_distance, TICK_LENGTH) * max_accel(heading(), -vec_between.angle());
accelerate(vec_between.normalize() * impulse);
}
} else if is_at_target {
accelerate(-velocity());
deactivate_ability(Ability::Boost);
} else {
debug!("Point ⚠️Not at target, but no fuel!⚠️");
}
}
if self.target_location.is_none() || is_at_target {
self.position_pid.idle();
}
if let Some(angle) = target_angle {
let error = angle_diff(heading(), angle);
self.angle_error = Some(error);
let force = self.angle_pid.solve(error, TICK_LENGTH);
torque(force);
}
if target_angle.is_none() {
self.angle_pid.idle();
}
}
pub fn orbit_distance(&mut self, distance: f64) {
self.orbit_distance = distance;
}
pub fn go_to(&mut self, location: Vec2) {
self.auto_angle = true;
self.infinite_accel = false;
self.target_angle = None;
self.target_location = Some(location);
}
pub fn fly_by(&mut self, location: Vec2) {
self.auto_angle = true;
self.infinite_accel = true;
self.target_angle = None;
self.target_location = Some(location);
}
pub fn point_at(&mut self, location: Vec2) {
self.auto_angle = false;
let vec_between = location - position();
self.target_angle = Some(vec_between.angle());
}
pub fn point_at_angle(&mut self, angle: f64) {
let indicator = position() + vec2(100.0, 0.0).rotate(angle);
self.auto_angle = false;
self.target_angle = Some(angle);
}
pub fn strafe_to(&mut self, location: Vec2) {
self.auto_angle = false;
self.target_location = Some(location);
}
pub fn target_ship(&mut self, ship: Option<Target>) {
}
pub fn angle_error(&self) -> Option<f64> {
self.angle_error
}
pub fn eta(&self) -> Option<f64> {
let target = self.target_location?;
let rel_target = target - position();
let approach = rel_target / velocity();
Some(approach.length())
}
pub fn distance(&self) -> Option<f64> {
Some((self.target_location? - position()).length())
}
pub fn builder() -> PointAutopilotBuilder {
PointAutopilotBuilder::new()
}
}
pub struct PointAutopilotBuilder {
allow_boost: bool,
} impl PointAutopilotBuilder {
pub fn new() -> Self {
PointAutopilotBuilder {
allow_boost: false,
}
}
pub fn build(self) -> PointAutopilot {
let mut out = PointAutopilot::new();
out.allow_boost = self.allow_boost;
out
}
pub fn allow_boost(mut self) -> Self {
self.allow_boost = true;
self
}
pub fn disallow_boost(mut self) -> Self {
self.allow_boost = false;
self
}
}
}

Possible translation

Please bear in mind that I haven't yet found the time to read the source code fully. Thus, I thought I'd ask directly.

  1. Is this game fully open-source? If so, will it stay that way?
  2. Is it possible to translate this game to other languages?

Thank you in advance for your time and consideration.

position() does not return the center of rotation

if the ship is not moving, but only rotating, the position() is changing

the difference is +-2 unit in each axis

use oort_api::prelude::*;

pub struct Ship {
    last_position: Vec2,
}

impl Ship {
    pub fn new() -> Ship {
        Ship {
            last_position: vec2(0.0, 0.0),
        }
    }

    pub fn tick(&mut self) {
        // position will change,but we are only turning!
        debug!("position {0}", position());
        turn(1000.0);
        if self.last_position != vec2(0.0, 0.0){
            draw_line(position(), self.last_position, 255);
        }
        if current_tick() % 100 == 0{
            self.last_position = position();
        }
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.