Changeset 346

Show
Ignore:
Timestamp:
05/30/08 08:24:53 (6 months ago)
Author:
FeepingCreature
Message:
  • Changed the path
  • Added ten lives functionality
  • Switched to more powerful selection system
  • Removed skewed circle functionality, was not needed
  • keystate and mouse state are always set
  • added blink() which is neat
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/qd/dt.d

    r345 r346  
    88import qd, dglut.vector; 
    99 
     10import tools.time; 
     11bool delegate() blink(float _delay) { 
     12  return stuple(_delay, true, sec()) /apply/ (float delay, ref bool state, ref float last) { 
     13    if (sec() < last) { 
     14      last = sec(); // timer wrapped around. Can't help this. Don't switch. Hope the user doesn't notice. 
     15      return state; 
     16    } 
     17    while (sec() - last > delay) { last += delay; state = !state; } 
     18    return state; 
     19  }; 
     20} 
     21 
    1022float randf() { return (cast(float)rand())/(cast(float)(typeof(rand()).max)); } 
    1123 
     
    1628  abstract void draw(); 
    1729  abstract void update(); 
     30} 
     31 
     32interface InteractingThing { 
     33  void select(); void unselect(); 
     34  void highlight(); void unhighlight(); 
     35  bool isSelected(); bool isHighlighted(); 
     36} 
     37 
     38template InteractingImpl() { 
     39  bool selected, highlighted; 
     40  void select() { selected = true; highlighted = true; } 
     41  void highlight() { highlighted = true; } 
     42  void unselect() { selected = false; } void unhighlight() { highlighted = false; } 
     43  bool isSelected() { return selected; } bool isHighlighted() { return selected || highlighted; } 
    1844} 
    1945 
     
    2854class LivingThing : WorldThing { 
    2955  private { 
    30     int life, age; 
     56    int life, maxlife, age; 
    3157    void delegate(LivingThing) onDeath; 
    3258  } 
     
    3460  void damage(int howmuch) { life-=howmuch; if (life!>0) onDeath(this); } 
    3561  void die() { damage(life); onDeath(this); } 
    36   mixin This!("onDeath, super(pos, radius), life=10"); 
     62  mixin This!("onDeath, super(pos, radius), life=10; #maxlife=life; "); 
    3763} 
    3864 
     
    108134 
    109135class Critter : LivingThing , MovingThing { 
    110   //void draw() { circle(x, y, radius, Black, Fill=Blue~White~White); } 
    111136  void draw() { 
    112137    bufferedCircle(pos.to!(int).tuple, radius, Black, Fill=Blue~White~White); 
     
    122147  void damage(typeof(life) d) { 
    123148    super.damage(d); 
    124     if (life!>0) addEffect!(RingEffect)(Blue~White~White, pos, 10, 15); 
     149    if (life!>0) { 
     150      addEffect!(RingEffect)(White~Yellow, pos, 10, 15); 
     151      addEffect!(RingEffect)(Black, pos, 11, 15); 
     152    } 
    125153  } 
    126154  void update() { 
     
    130158  float speed; 
    131159  void delegate() win; 
     160  void done() { win(); die(); } 
    132161  private { 
    133     int maxlife; 
    134162    Path path; 
    135163    Path.Train train; 
    136164    void initTrain() { 
    137       train=path.new Train(pos, speed, win); 
     165      train=path.new Train(pos, speed, &done); 
    138166    } 
    139167    long id; 
    140168  } 
    141   mixin This!("path, speed, win, id, super(onDeath, pos, radius=20, life=20), #maxlife=life; #initTrain; "); 
     169  mixin This!("path, speed, win, id, super(onDeath, pos, radius=20, life=20), #initTrain; "); 
    142170} 
    143171 
     
    280308} 
    281309 
    282 class Turret : WorldThing { 
     310class Turret : WorldThing, InteractingThing { 
     311  mixin InteractingImpl!(); 
    283312  struct Settings { 
    284313    int range, rate; 
     
    296325  void draw() { 
    297326    auto ipos = pos.to!(int); 
    298     if (mouseOver(this)) { 
     327    if (isHighlighted) { 
    299328      circle(ipos.tuple, settings.range+1, White); 
    300329      circle(ipos.tuple, settings.range, Black); 
    301330      circle(ipos.tuple, settings.range-1, White); 
    302331    } 
    303     bufferedCircle(ipos.tuple, radius, Black, Fill=White~Green); 
     332    if (isSelected) bufferedCircle(ipos.tuple, radius, Black, Fill=White~Green~(Blue~White)); 
     333    else bufferedCircle(ipos.tuple, radius, Black, Fill=White~Green); 
    304334    Teh_Ordnance.draw; 
    305335  } 
     
    342372    bool break_mode; 
    343373    Path path; 
     374    int score; 
     375    void delegate() critter_hit; 
    344376  } 
    345377  TargetGroup critters; 
    346   mixin This!("rate, groupsize, breaktime, life, path, super(pos, radius=15), #counter=0; 
     378  mixin This!("rate, groupsize, breaktime, life, critter_hit, path, super(pos, radius=15), #counter=0; 
    347379    #group_left=groupsize; #critters=new TargetGroup; #break_mode=true; #break_left=breaktime; "); 
    348380  void draw() { 
     
    354386    else if (group_left) text = Format(group_left); 
    355387    critters.draw; 
    356     withSet(alpha, 64, { circle(pos.to!(int).tuple, radius, White, Fill=Background~Black); }); 
     388    withSet(alpha, 64, { 
     389      circle(pos.to!(int).tuple, radius, Fill=Background~Black); 
     390    }); 
    357391    .print(pos.to!(int).tuple, Center, Black, text); 
    358392  } 
    359   void win() { throw new Exception("The critters win!"); } 
     393  void win() { critter_hit(); } 
    360394  static long id=0; 
    361395  void update() { 
     
    378412    } else group_left --; 
    379413    // yes the last critter is intentionally stronger. 
    380     auto newCritter=new Critter(path, 0.6, &win, id++, &critters.removeAs!(LivingThing), pos, 10, cast(int) life); 
     414    auto newCritter=new Critter(path, 0.5, &win, id++, 
     415      stuple(critters, this) /apply/ (TargetGroup tg, typeof(this) This, LivingThing lt) { tg.remove(cast(Critter) lt); This.score += lt.maxlife; }, 
     416      pos, 10, cast(int) life); 
    381417    critters.addThing(newCritter); newCritter.update; 
    382418  } 
     
    441477} 
    442478 
    443 bool delegate(WorldThing) mouseOver; 
     479class InteractionSet { 
     480  alias InteractingThing IT; 
     481  bool[IT] selected, highlighted; 
     482  void cleanHighlights() { foreach (entry; highlighted.keys) entry.unhighlight; highlighted = null; } 
     483  void cleanSelection() { foreach (entry; selected.keys) entry.unselect; selected = null; } 
     484  void rmHighlight(IT it) { it.unhighlight; highlighted.remove(it); } 
     485  void addHighlight(IT it) { highlighted[it] = true; it.highlight; } 
     486  void mouse_up() { 
     487    if (!(SDLKey.LCtrl in keystate)) cleanSelection; 
     488    foreach (entry; highlighted.keys) { 
     489      entry.select; 
     490      selected[entry] = true; 
     491    } 
     492    cleanHighlights(); 
     493  } 
     494
    444495 
    445496import test13, tools.functional; 
    446497void main() { 
     498  auto blink_fn = blink(0.5); 
    447499  vec2f mouse_pos, start; 
    448500  bool drag=false; 
    449501  bool[int] pressed; 
    450   WorldThing[] select; 
    451   auto moveMouseOver=(WorldThing w) { 
    452     foreach (s; select) if (w is s) return true; 
    453     with (w) return ((pos - mouse_pos).length()<=radius); 
    454   }; 
    455   auto dragMouseOver=(WorldThing wt) { 
    456     if (SDLKey.LCtrl in pressed) foreach (s; select) if (wt is s) return true; 
     502  auto thingies = new InteractionSet; 
     503  bool underMouse(WorldThing wt) { 
     504    with (wt) return (pos - mouse_pos).length() <= radius; 
     505  } 
     506  bool underSelection(WorldThing wt) { 
     507    logln(cast(void*) wt, " under selection?"); 
    457508    with (wt) { 
    458509      if (pos.x+radius<min(start.x, mouse_pos.x)) return false; 
     
    461512      if (pos.y-radius>max(start.y, mouse_pos.y)) return false; 
    462513    } 
     514    logln(cast(void*) wt, " under selection."); 
    463515    return true; 
    464   }; 
    465   mouseOver=moveMouseOver; 
     516  } 
    466517  screen(640, 480); 
    467518  while (!mouse.clicked) { flip; events; } 
     
    469520  Group!(Thing) group; 
    470521  auto path=new Path(false, 
    471     vec2f(30, 30), vec2f(300, 30), vec2f(300, 300), vec2f(30, 300), vec2f(30, 90) 
     522    vec2f(60, 60), vec2f(60, 300), vec2f(200, 300), vec2f(200, 30), 
     523      vec2f(440, 30), vec2f(440, 150), vec2f(300, 150), vec2f(300, 300), vec2f(500, 300) 
    472524  ); 
    473525   
    474526  auto bg_surf = screen.With(screen.w, screen.h) = { 
    475527    FatLine fl; 
    476     fl = new FatLine(vec2f(300, 400) ~ path.points, (float d) { 
     528    fl = new FatLine(path.points, (float d) { 
    477529      if (abs(d) > fl.width) return Background; 
    478530      else if (abs(d) > fl.width - 2) return Background.blend(Black, (fl.width - abs(d)) / 2f); 
     
    483535  }; 
    484536   
    485   auto spawner=new SpawnPoint(/* rate */ 48, /* groupsize */ 10, /* breaktime */ 5, /* start life */ 64, path, vec2f(300, 400)); 
     537  int hits_counter = 10; 
     538  void hit() { 
     539    hits_counter --; 
     540    if (!hits_counter) throw new Exception("You lose!"); 
     541  } 
     542  auto spawner=new SpawnPoint(/* rate */ 48, /* groupsize */ 10, /* breaktime */ 5, /* start life */ 64, &hit, path, path.points[0]); 
    486543  group=new typeof(group)([cast(Thing)spawner]); 
    487544  group.addThing(new Turret( 
    488545    Turret.Settings(115, 24, false), 
    489546    Ammo.Settings(/*speed*/ 1.5f, /*aim*/ 0.25, /*momentum_speed*/0, /*momentum_dir*/ 1, /*damage*/ 8, /*lifetime*/256, /*linger*/true, /*punchthrough*/false), 
    490     spawner.critters, vec2f(85, 220) 
     547    spawner.critters, vec2f(30, 340) 
    491548  )); 
    492549  group.addThing(new Turret( 
    493     Turret.Settings(115, 6, true), 
     550    Turret.Settings(115, 12, false), 
    494551    Ammo.Settings(/*speed*/ 0.9f, /*aim*/ 0, /*momentum_speed*/0.9, /*momentum_dir*/ 0.98, /*damage*/ 2, /*lifetime*/1024, true, false, true), 
    495     spawner.critters, vec2f(185, 135) 
     552    spawner.critters, vec2f(360, 85) 
    496553  )); 
    497554  group.addThing(effects); 
     
    502559  scope(exit) writefln("Average FPS: ", avg/(cast(float)count)); 
    503560  auto limiter=new FrameLimiter(60, 60); 
     561  bool delegate(WorldThing) shouldHighlight = &underMouse;; 
    504562  do with (group) { 
    505563    update; 
     
    507565    display.blit(bg_surf); 
    508566    prettyprint(0, 0, Bottom|Right, 
    509       "Test .. [size -1]test![/size] [b]Bold, [i]italic and [u]underlined![/u][/i][/b] [i]Just italic now.[/i] [b][color #f00]Red?[/color][/b]Done!"); 
     567      Format("Score: [b][size -2]", spawner.score, "[/size][/b]")); 
    510568    draw; 
     569    withSet(alpha, 64, { circle(path.points[$-1].to!(int).tuple, 15, Fill=Yellow~Black); }); 
     570    string formatting = Format(hits_counter); 
     571    auto b = blink_fn(); 
     572    if (hits_counter <= 3) formatting = "[size +4]"~(b?"[color #f88][b]":"")~formatting~(b?"[/b][/color]":"")~"[/size]"; 
     573    formatting = "[color #c80]"~formatting~"[/color]"; 
     574    .prettyprint(path.points[$-1].to!(int).tuple, Center, formatting); 
    511575    if (drag) { 
    512576      tintfill(start.min(mouse_pos).to!(int).tuple, start.max(mouse_pos).to!(int).tuple, Blue~White); 
     
    520584      if (key==27) throw new Error("Quit"); 
    521585    }, (int x, int y, ubyte button, int p) { 
     586      foreach (thing; group) { 
     587        auto wt = cast(WorldThing) thing, it = cast(InteractingThing) thing; 
     588        if (wt && it) 
     589          if (shouldHighlight(wt)) thingies.addHighlight(it); 
     590          else thingies.rmHighlight(it); 
     591      } 
    522592      if (!button) { 
    523593        mouse_pos.x=x; mouse_pos.y=y; 
     
    525595        if (p==1) { 
    526596          start.x=x; start.y=y; 
    527           mouseOver=dragMouseOver; 
    528597          drag=true; 
     598          shouldHighlight = &underSelection; 
    529599        } 
    530600        if (p==-1) { 
    531           if (!(SDLKey.LCtrl in pressed)) select=null; 
    532           foreach (critter; group) if (auto wt=cast(WorldThing) critter) if (mouseOver(wt)) select~=wt; 
    533           mouseOver=moveMouseOver; 
     601          thingies.mouse_up; 
     602          shouldHighlight = &underMouse; 
    534603          drag=false; 
    535604        } 
     
    546615      fps=0; 
    547616    } 
    548     // with (Background) SDL_FillRect(display.surface, null, SDL_MapRGBA(display.surface.format, values[0], values[1], values[2], 0)); 
    549617  } while (true); 
    550618} 
  • trunk/qd/qd.d

    r345 r346  
    441441  const string yx=(first?"y":"x"); 
    442442  const string str=" 
    443     auto x="~(first?"xradius":"0")~"; 
    444     auto y="~(first?"0":"yradius")~"; 
    445     auto xchange=yradius*yradius*"~(first?"(1-2*xradius)":"1")~"; 
    446     auto ychange=xradius*xradius*"~(first?"1":"(1-2*yradius)")~"; 
     443    auto x="~(first?"radius":"0")~"; 
     444    auto y="~(first?"0":"radius")~"; 
     445    auto xchange=radius*radius*"~(first?"(1-2*radius)":"1")~"; 
     446    auto ychange=radius*radius*"~(first?"1":"(1-2*radius)")~"; 
    447447    auto error=0; 
    448     auto stopx="~(first?"y2square*xradius":"0")~"; 
    449     auto stopy="~(first?"0":"x2square*yradius")~"; 
     448    auto stopx="~(first?"y2square*radius":"0")~"; 
     449    auto stopy="~(first?"0":"x2square*radius")~"; 
    450450    while (stopx"~(first?">=":"<=")~"stopy) { 
    451451      putpixel(cx+x, cy+y, col); 
     
    486486void circle(T...)(T t) { 
    487487  static assert(T.length!<3, "Circle: Needs x, y and radius"); 
    488   int cx=cast(int)t[0], cy=cast(int)t[1], xradius=cast(int)t[2]; 
     488  int cx=cast(int)t[0], cy=cast(int)t[1], radius=cast(int)t[2]; 
    489489  SDL_LockSurface(display.surface); 
    490490  scope(exit) { SDL_UnlockSurface(display.surface); if (doFlip) flip; } 
    491491  execParams(t[3..$]); 
    492   auto yradius=xradius; 
    493   if (xradius!>0) return; 
     492  if (radius!>0) return; 
    494493  static if (T.length>3 && is(T[3]: int)) yradius=t[3]; 
    495494  static if (Select!(back_rgb, T) != -1) { 
    496     auto ratio=xradius*1f/yradius; 
    497495    auto back_sdl=SDL_MapRGBA(display.surface.format, back.values[0], back.values[1], back.values[2], 0); 
    498     for (int i=0; i<=yradius; ++i) { 
    499       ushort j=cast(ushort)(sqrt(cast(real)(yradius*yradius-i*i))*ratio); 
     496    for (int i=0; i<=radius; ++i) { 
     497      ushort j=cast(ushort)(sqrt(cast(real)(radius*radius-i*i))); 
    500498      hline(cx-j, cy+i, 2*j, back_sdl); 
    501       hline(cx-j, cy-i, 2*j, back_sdl); 
    502     } 
    503   } 
    504   auto x2square=2*xradius*xradius; 
    505   auto y2square=2*yradius*yradius; 
    506   uint col=SDL_MapRGBA(display.surface.format, color.values[0], color.values[1], color.values[2], 0); 
    507   { mixin(circle_bresenham_pass!(true).str); } 
    508   { mixin(circle_bresenham_pass!(false).str); } 
     499      if (i) hline(cx-j, cy-i, 2*j, back_sdl); 
     500    } 
     501  } 
     502  static if (Select!(back_rgb, T) == -1 || Select!(rgb, T) != -1) { 
     503    auto x2square=2*radius*radius, y2square=x2square; 
     504    uint col=SDL_MapRGBA(display.surface.format, color.values[0], color.values[1], color.values[2], 0); 
     505    { mixin(circle_bresenham_pass!(true).str); } 
     506    { mixin(circle_bresenham_pass!(false).str); } 
     507  } 
    509508} 
    510509 
     
    622621} 
    623622 
     623bool[int] keystate; 
     624 
    624625/// parameters to key: which key, and if it's pressed or released 
    625626/// parameters to mouse: x, y, button [Left: 1, Mid: 2, Right: 3], change [1: pressed, -1: released] 
     
    629630    switch (evt.type) { 
    630631      case SDL_EventType.MouseMotion: 
    631         with (evt.motion) if (mouse) mouse(x, y, 0, 0); else updateMouse(x, y, 0, 0); 
     632        with (evt.motion) { 
     633          updateMouse(x, y, 0, 0); 
     634          if (mouse) mouse(x, y, 0, 0); 
     635        } 
    632636        break; 
    633637      case SDL_EventType.MouseButtonDown: 
    634         with (evt.button) if (mouse) mouse(x, y, button, 1); else updateMouse(x, y, button, 1); 
     638        with (evt.button) { 
     639          updateMouse(x, y, button, 1); 
     640          if (mouse) mouse(x, y, button, 1); 
     641        } 
    635642        break; 
    636643      case SDL_EventType.MouseButtonUp: 
    637         with (evt.button) if (mouse) mouse(x, y, button, -1); else updateMouse(x, y, button, -1); 
     644        with (evt.button) { 
     645          updateMouse(x, y, button, -1); 
     646          if (mouse) mouse(x, y, button, -1); 
     647        } 
    638648        break; 
    639649      case SDL_EventType.KeyDown: 
     650        keystate[evt.key.keysym.sym] = true; 
    640651        if (key) key(evt.key.keysym.sym, true); 
     652        break; 
    641653      case SDL_EventType.KeyUp: 
     654        keystate.remove(evt.key.keysym.sym); 
    642655        if (key) key(evt.key.keysym.sym, false); 
    643656        break;