summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorrealtradam <[email protected]>2022-02-23 01:27:20 -0500
committerrealtradam <[email protected]>2022-02-23 01:27:20 -0500
commit199a7b1ddca336ab0d357131682927c08ee5b853 (patch)
treefb296060bb572e63ef39482d45b632f9b24822f8
downloadhextile-system-demo-199a7b1ddca336ab0d357131682927c08ee5b853.tar.gz
hextile-system-demo-199a7b1ddca336ab0d357131682927c08ee5b853.zip
-rw-r--r--README.mdown9
-rw-r--r--assets/.empty0
-rw-r--r--main.rb264
3 files changed, 273 insertions, 0 deletions
diff --git a/README.mdown b/README.mdown
new file mode 100644
index 0000000..0f01c99
--- /dev/null
+++ b/README.mdown
@@ -0,0 +1,9 @@
+# HexTile System Demo
+
+Simple demo showing the following:
+- Creating a 2D array of hex tiles
+- Rendering the array of hex tiles in proper order
+- Hit detection of when a mouse is over a hex
+- Being able to get and modify adjacent tiles
+
+Mouse over the the tiles to see the magic.
diff --git a/assets/.empty b/assets/.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/assets/.empty
diff --git a/main.rb b/main.rb
new file mode 100644
index 0000000..3a16a06
--- /dev/null
+++ b/main.rb
@@ -0,0 +1,264 @@
+GameName = 'Hextest'
+Rl.init_window(800, 600, GameName)
+
+include FECS
+
+Cmp.new('Shape', :obj)
+Cmp.new('ShapeColor', :color)
+Cmp.new('BorderColor', :color)
+
+class Shape
+ attr_reader :angle, :size, :x, :y, :sides
+ def initialize(angle: 0, size: 0, x: 0, y: 0, sides: 3)
+ @sides = sides
+ @angle = angle
+ @size = size
+ @x = x
+ @y = y
+ update
+ end
+
+ def points
+ @points ||= []
+ end
+
+ def sides=(sides)
+ @sides = sides
+ self.update
+ end
+
+ def angle=(angle)
+ @angle = angle
+ self.update
+ end
+
+ def size=(size)
+ @size = size
+ self.update
+ end
+
+ def x=(x)
+ @x = x
+ self.update
+ end
+
+ def y=(y)
+ @y = y
+ self.update
+ end
+
+ private
+ def update
+ sides.times do |point_num|
+ points[point_num] ||= Hash.new
+ points[point_num][:x] = Math.sin(((point_num/sides.to_f) * Math::PI * 2) - angle) * size + x
+ points[point_num][:y] = Math.cos(((point_num/sides.to_f) * Math::PI * 2) - angle) * size + y
+ end
+ [sides - points.length, 0].max.times do
+ points.pop # strip extra points
+ end
+ end
+end
+
+MouseFollow = Cmp::Shape.new(obj: Shape.new(sides: 3, size: 1))
+Ent.new(MouseFollow)
+
+Sys.new('InitGrid') do
+ GameHexArray = Array.new(5) do |x|
+ Array.new(5) do |y|
+ x_thingie = 90
+ Ent.new(
+ Cmp::Shape.new(
+ obj: Shape.new(
+ x: (x * x_thingie) + (y * (x_thingie/2)) + 150,
+ y: (y * 50) + (y * 30) + 150,
+ sides: 6,
+ size: 50
+ )
+ ),
+ Cmp::ShapeColor.new(color: Rl::Color.ray_white),
+ Cmp::BorderColor.new(color: Rl::Color.dodger_blue)
+ )
+ end
+ end
+end
+
+Sys::InitGrid.call
+
+Sys.new('DrawShape') do
+ Ent.group(Cmp::Shape, Cmp::ShapeColor, Cmp::BorderColor) do |shape_cmp, color_cmp, border_color_cmp, entity|
+ shape = shape_cmp.obj
+ Rl.draw_poly(center: Rl::Vector2.new(shape.x, shape.y),
+ radius: shape.size,
+ sides: shape.sides,
+ rotation: shape.angle,
+ color: color_cmp.color)
+ Rl.draw_poly_lines(center: Rl::Vector2.new(shape.x, shape.y),
+ radius: shape.size,
+ sides: shape.sides,
+ rotation: shape.angle,
+ color: border_color_cmp.color,
+ line_thickness: shape.size/10)
+ border_color_cmp.color = Rl::Color.dodger_blue
+ color_cmp.color = Rl::Color.ray_white
+ end
+end
+
+Sys.new('MouseOver') do
+ MouseFollow.obj.x = Rl.mouse_x
+ MouseFollow.obj.y = Rl.mouse_y
+ mouse_points = Array.new(MouseFollow.obj.sides) do |side|
+ [MouseFollow.obj.points[side][:x],
+ MouseFollow.obj.points[side][:y]]
+ end
+
+ #Ent.group(Cmp::Shape, Cmp::ShapeColor, Cmp::BorderColor) do |shape_cmp|
+ GameHexArray.each_with_index do |arry, x|
+ arry.each_with_index do |shape_ent, y|
+ shape = shape_ent.component[Cmp::Shape]
+ if SAT.hitbox_check(
+ mouse_points,
+ Array.new(shape.obj.sides) do |side|
+ [shape.obj.points[side][:x],
+ shape.obj.points[side][:y]]
+ end
+ )
+ shape_ent.component[Cmp::BorderColor].color = Rl::Color.red
+ shape_ent.component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ unless y == 0
+ GameHexArray[x][y-1].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x][y-1].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ unless GameHexArray[x+1].nil?
+ GameHexArray[x+1][y-1].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x+1][y-1].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ end
+ end
+ unless GameHexArray[x+1].nil?
+ GameHexArray[x+1][y].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x+1][y].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ end
+ unless GameHexArray[x][y+1].nil?
+ GameHexArray[x][y+1].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x][y+1].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ unless x == 0
+ GameHexArray[x-1][y+1].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x-1][y+1].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ end
+ end
+ unless x == 0
+ GameHexArray[x-1][y].component[Cmp::BorderColor].color = Rl::Color.red
+ GameHexArray[x-1][y].component[Cmp::ShapeColor].color = Rl::Color.fire_brick
+ end
+ end
+ end
+ end
+end
+
+module SAT
+ class << self
+ # The hitbox logic
+ def hitbox_check(shape_a, shape_b)
+ # Get normals of both shapes
+ inverted = build_inverted_edges(shape_a)
+ inverted.concat(build_inverted_edges(shape_b))
+
+ inverted.each_with_index do |line, line_index|
+ # Determine max and min of a and b shapes
+ amax, amin = calculate_minmax(shape_a, line)
+ bmax, bmin = calculate_minmax(shape_b, line)
+
+ if ((amin <= bmax) && (amin >= bmin)) || ((bmin <= amax) && (bmin >= amin))
+ next
+ else
+ return false
+ end
+ end
+ true
+ end
+
+ # Creates edges out using coordinates and then gets the normal
+ def build_inverted_edges(shape)
+ edges = []
+ shape.each_with_index do |vertex_start, index|
+ vertex_end = if index == shape.length - 1
+ shape[0]
+ else
+ shape[index + 1]
+ end
+ edges.push [vertex_end[1] - vertex_start[1],
+ -(vertex_end[0] - vertex_start[0])]
+ end
+ edges
+ end
+
+ # Dot product
+ def vecDotProd(a, b)
+ (a[0] * b[0]) + (a[1] * b[1])
+ end
+
+ # Calculates the minimum point and maximum point projected onto the line
+ def calculate_minmax(shape, line)
+ min = vecDotProd(shape.first, line)
+ max = vecDotProd(shape.first, line)
+ shape.each_with_index do |vertex, _vertex_index|
+ dot = vecDotProd(vertex, line)
+ if dot > max
+ max = dot
+ elsif dot < min
+ min = dot
+ end
+ end
+ [max, min]
+ end
+ end
+end
+
+Rl.target_fps = 60
+Rl.while_window_open do
+ #if Rl.key_pressed? 61 # plus/equal
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.sides += 1 unless Target.obj.sides == 9
+ # else
+ # MouseFollow.obj.sides += 1 unless MouseFollow.obj.sides == 9
+ # end
+ #end
+ #if Rl.key_pressed? 45 # minus/underscore
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.sides -= 1 unless Target.obj.sides == 3
+ # else
+ # MouseFollow.obj.sides -= 1 unless MouseFollow.obj.sides == 3
+ # end
+ #end
+ #if Rl.key_down? 65 # a
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.angle -= (Math::PI/180) * 2
+ # else
+ # MouseFollow.obj.angle -= (Math::PI/180) * 2
+ # end
+ #end
+ #if Rl.key_down? 68 # d
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.angle += (Math::PI/180) * 2
+ # else
+ # MouseFollow.obj.angle += (Math::PI/180) * 2
+ # end
+ #end
+ #if Rl.key_down? 87 # w
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.size += 1
+ # else
+ # MouseFollow.obj.size += 1
+ # end
+ #end
+ #if Rl.key_down? 83 # s
+ # if (Rl.key_down? 340) || (Rl.key_down? 344)
+ # Target.obj.size -= 1
+ # else
+ # MouseFollow.obj.size -= 1
+ # end
+ #end
+ Rl.draw(clear_color: Rl::Color.black) do
+ Sys::MouseOver.call
+ Sys::DrawShape.call
+ end
+end