so://phie

game-engine

A lightweight JavaScript game engine
git clone git://soophie.de/game-engine

blob: b1f9322f9ab6b764c318806f2ba75d9250ed4228 (3710 bytes)[doc][blame][raw]

1import { scaleCanvas } from './canvas.js';

2import * as Collision from './collision.js';

3

4export class Game {

5 constructor(width, height, { fps } = {}) {

6 this.width = width || 900;

7 this.height = height || 600;

8 this.fps = 1000 / (fps || 60);

9 this.then = Date.now();

10 this.canvas = document.createElement('canvas');

11 scaleCanvas(this.canvas, this.width, this.height);

12 this.g = this.canvas.getContext('2d');

13 this.events = new Proxy({}, {

14 get: function(object, prop) {

15 const val = object[prop];

16 if(typeof val !== 'undefined') {

17 delete object[prop];

18 }

19 return val;

20 }

21 });

22 }

23 start() {

24 requestAnimationFrame(this.loop.bind(this));

25 this.update();

26 this.g.save();

27 this.render(this.g);

28 this.g.restore();

29 }

30 loop() {

31 requestAnimationFrame(this.loop.bind(this));

32 this.now = Date.now();

33 this.elapsed = this.now - this.then;

34 if(this.elapsed > this.fps) {

35 this.then = this.now - (this.elapsed % this.fps);

36 this.update();

37 this.g.save();

38 this.render(this.g);

39 this.g.restore();

40 }

41 }

42 update() {

43 // empty

44 }

45 render() {

46 this.g.clearRect(0, 0, this.width, this.height);

47 }

48 resize(width, height) {

49 this.width = width;

50 this.height = height;

51 scaleCanvas(this.canvas, this.width, this.height);

52 }

53 bindEvent(element, event) {

54 element[event] = event => {

55 this.events[event.type] = this.populateEvent ? { type: event.type, ...this.populateEvent(event) } : event;

56 }

57 }

58}

59

60export class Group {

61 constructor() {

62 this.items = [];

63 }

64 update() {

65 for(let item of this.items) {

66 item.update();

67 }

68 }

69 render(g) {

70 for(let item of this.items) {

71 g.save();

72 item.render(g);

73 g.restore();

74 }

75 }

76 collide() {

77 for(const i of this.items) {

78 i.items = [];

79 i.collided = false;

80 }

81 const duplicate = [];

82 for(const a of this.items) {

83 for(const b of this.items) {

84 if(!duplicate.includes(b)) {

85 if(a !== b) {

86 let collided = false;

87 if(a.shape instanceof Shape.Rect && b.shape instanceof Shape.Rect) {

88 collided = Collision.collideRect(a, b);

89 }

90 else if(a.shape instanceof Shape.Circle && b.shape instanceof Shape.Circle) {

91 collided = Collision.collideCircle(a, b);

92 }

93 else {

94 collided = Collision.collideRectAndCircle(a, b);

95 }

96 if(!a.collided) {

97 a.collided = collided;

98 }

99 if(!b.collided) {

100 b.collided = collided;

101 }

102 if(collided) {

103 if(!a.items.includes(b)) {

104 a.items.push(b);

105 }

106 if(!b.items.includes(a)) {

107 b.items.push(a);

108 }

109 }

110 }

111 }

112 }

113 duplicate.push(a);

114 }

115 }

116 add(item) {

117 this.items.push(item);

118 }

119 remove(item) {

120 const i = this.items.findIndex(n => n === item);

121 if(i !== -1) {

122 this.items.splice(i, 1);

123 }

124 }

125 [Symbol.iterator]() {

126 return this.items.values();

127 }

128}

129

130export class Surface {

131 constructor(x, y, shape) {

132 this.x = x;

133 this.y = y;

134 this.shape = shape;

135 this.events = new Proxy({}, {

136 get: function(object, prop) {

137 const val = object[prop];

138 if(typeof val !== 'undefined') {

139 delete object[prop];

140 }

141 return val;

142 }

143 });

144 }

145 update() {

146 // empty

147 }

148 render(g) {

149 if(this.shape instanceof Shape.Rect) {

150 g.beginPath();

151 g.rect(this.x, this.y, this.shape.width, this.shape.height);

152 g.stroke();

153 }

154 if(this.shape instanceof Shape.Circle) {

155 g.beginPath();

156 g.arc(this.x, this.y, this.shape.radius, 2 * Math.PI, 0);

157 g.stroke();

158 }

159 }

160 causeEvent(event) {

161 this.events[event.type] = event;

162 }

163}

164

165class Rect {

166 constructor(width, height) {

167 this.width = width;

168 this.height = height;

169 }

170}

171

172class Circle {

173 constructor(radius) {

174 this.radius = radius;

175 }

176}

177