module dconf.ronaroids.base; import std.math; struct PolarCoord { float a = 0.0f; float r = 0.0f; } private PolarCoord[] roundObject(int segmentsCount, bool convex) { assert(__ctfe); PolarCoord[] items; float a = 0; float step = PI * 2 / segmentsCount; foreach(i; 0 .. segmentsCount) { items ~= PolarCoord(a, (!convex || i%2) ? 1.0 : 0.5); a += step; } items ~= items[0]; return items; } static immutable PolarCoord[] shipVertexes = [ PolarCoord(0.0, 0), PolarCoord(PI - PI / 6, 1.0), PolarCoord(0, 1.0), PolarCoord(PI + PI / 6, 1.0), PolarCoord(0.0, 0) ]; static immutable PolarCoord[] asteroidVertexes = roundObject(12, true); static immutable PolarCoord[] bulletVertexes = roundObject(12, false); immutable struct GameObjectDefinition { PolarCoord[] vertexes; float radius; } static immutable GameObjectDefinition[] gameObjectTypes = [ GameObjectDefinition(shipVertexes, 16), GameObjectDefinition(bulletVertexes, 4), GameObjectDefinition(asteroidVertexes, 24), GameObjectDefinition(asteroidVertexes, 12), GameObjectDefinition(asteroidVertexes, 6), ]; struct GameObject { align(1): ubyte owner; // 0 == neutral ubyte type; // ship, bullet, asteroids of various sizes. short hp; ushort controlState; short cooldown; float x, y, a; float dx, dy, da; } struct GameUpdate { int time; GameObject[] state; } struct ControlUpdate { int time; // this is likely ignored as the server is the source of truth ushort newControlState; ushort newControlStateMask; // tells which ones are actually changed ubyte owner; } version(WebAssembly) version=client; version(client): import arsd.simpledisplay; import arsd.http2; void main() { auto window = new SimpleWindow(512, 512); GameObject[] objects; objects ~= GameObject(1, 0, 1200, 0, 0, 100, 100, 0, 0, 0, 0); objects ~= GameObject(0, 2, 1200, 0, 0, 300, 300, 0, 0.2, -0.2, 0); /+ auto ws = new WebSocket(Uri("ws://arsdnet.net:8080/")); ws.addToSimpledisplayEventLoop!()(window); ws.onmessage = (in ubyte[] data) { ControlUpdate* cu = cast(ControlUpdate*) data.ptr; if(cu.newControlState == 0x01) objects[0].da -= 0.01; if(cu.newControlState == 0x02) objects[0].da += 0.01; }; ws.connect(); +/ //ubyte[] msg = [1,2,3]; //ws.send(msg); window.eventLoop(1000 / 60, delegate (KeyEvent ev) { switch(ev.key) { case Key.Left: ControlUpdate cu; cu.time = 0; cu.newControlState = 0x01; cu.newControlStateMask = 0x01; cu.owner = 1; //ws.send((cast(ubyte*) &cu)[0 .. cu.sizeof]); objects[0].da -= 0.01; break; case Key.Right: ControlUpdate cu; cu.time = 0; cu.newControlState = 0x02; cu.newControlStateMask = 0x02; cu.owner = 1; //ws.send((cast(ubyte*) &cu)[0 .. cu.sizeof]); objects[0].da += 0.01; break; case Key.Up: objects[0].dx += 0.05 * cos(objects[0].a); objects[0].dy += 0.05 * sin(objects[0].a); break; case Key.Space: if(ev.pressed) objects ~= GameObject( 1, 1, 100, 0, 0, objects[0].x + 16 * 1.5 * cos(objects[0].a), objects[0].y + 16 * 1.5 * sin(objects[0].a), 0, objects[0].dx + 2 * cos(objects[0].a), objects[0].dy + 2 * sin(objects[0].a), 0 ); break; default: } }, () { auto painter = window.draw(); painter.fillColor = Color.black; painter.outlineColor = Color.black; painter.drawRectangle(Point(0, 0), Size(window.width, window.height)); foreach(ref obj; objects) { painter.fillColor = Color.white; painter.outlineColor = Color.white; obj.x += obj.dx; obj.y += obj.dy; obj.a += obj.da; auto type = gameObjectTypes[obj.type]; foreach(i, vertex; type.vertexes[0 .. $-1]) { painter.drawLine( Point( cast(int) (type.radius * vertex.r * cos(obj.a + vertex.a) + obj.x), cast(int) (type.radius * vertex.r * sin(obj.a + vertex.a) + obj.y) ), Point( cast(int) (type.radius * type.vertexes[i + 1].r * cos(obj.a + type.vertexes[i + 1].a) + obj.x), cast(int) (type.radius * type.vertexes[i + 1].r * sin(obj.a + type.vertexes[i + 1].a) + obj.y) ) ); } } } ); }